From 34536002e04c34d57929130a1ae79e1acc621f9c Mon Sep 17 00:00:00 2001 From: Shashwat Gupta Date: Thu, 19 Oct 2023 23:20:02 +0530 Subject: [PATCH 01/31] fix: removed the docker part from readme (#5) Signed-off-by: Shashwat79802 --- django-postgres/README.md | 18 ++---------------- .../django_postgres/application/views.py | 5 ++++- 2 files changed, 6 insertions(+), 17 deletions(-) diff --git a/django-postgres/README.md b/django-postgres/README.md index 6d3f815..16d6192 100644 --- a/django-postgres/README.md +++ b/django-postgres/README.md @@ -1,6 +1,6 @@ # User Data CRUD Application -A sample user data CRUD app to test Keploy integration capabilities using [Django](https://www.djangoproject.com/) and PostgreSQL.
+A sample user data CRUD app to test Keploy integration capabilities using [Django](https://www.djangoproject.com/) and [PostgreSQL](https://www.postgresql.org/).
Make the following requests to the respective endpoints - 1. `GET /user/` - To get all the data at once. @@ -138,18 +138,4 @@ Now let's run the application in test mode. sudo -E keploy test -c "python3 manage.py runserver" --delay 10 ``` -So no need to setup fake database/apis like Postgres or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Postgres 😄** - -# Using Docker - -Keploy can be used on Linux & Windows through Docker, and on MacOS by the help of [Colima](https://docs.keploy.io/docs/server/macos/installation/#using-colima) - -## Create Keploy Alias - -To establish a network for your application using Keploy on Docker, follow these steps. - -If you're using a docker-compose network, replace keploy-network with your app's `docker_compose_network_name` below. - -```shell -alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock --rm ghcr.io/keploy/keploy' -``` +So, no need to setup fake database/apis like Postgres or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Postgres 😄** diff --git a/django-postgres/django_postgres/application/views.py b/django-postgres/django_postgres/application/views.py index 6bea49c..2c1ff2b 100644 --- a/django-postgres/django_postgres/application/views.py +++ b/django-postgres/django_postgres/application/views.py @@ -38,13 +38,16 @@ def get_update_deleteUser(request, uuid: uuid4): return JsonResponse({"message": "User Deleted!!"}) except Exception as e: return JsonResponse({"message": str(e)[2:-2]}) - + + @api_view(["GET", "POST"]) def getAll_createUser(request): if request.method == "GET": try: data = UserSerializer(User.objects.all(), many=True) + if data.data == []: + return JsonResponse({"message": "No Users Found!!"}) return Response(data.data) except Exception as e: return JsonResponse({"message": str(e)}) From 73af76f6356149788a57f62e8680915084575323 Mon Sep 17 00:00:00 2001 From: Shashwat Gupta Date: Tue, 24 Oct 2023 07:57:45 +0530 Subject: [PATCH 02/31] feat: adding new sample app for python (#7) * fix: removed the docker part from readme Signed-off-by: Shashwat79802 * feat: adding new samples app for python Signed-off-by: Shashwat79802 --------- Signed-off-by: Shashwat79802 --- fastapi-postgres/.gitignore | 2 + fastapi-postgres/Dockerfile | 30 + fastapi-postgres/README.md | 124 ++ fastapi-postgres/application/__init__.py | 0 fastapi-postgres/application/crud.py | 52 + fastapi-postgres/application/database.py | 11 + fastapi-postgres/application/main.py | 59 + fastapi-postgres/application/models.py | 13 + fastapi-postgres/application/schemas.py | 24 + fastapi-postgres/data.json | 53 + fastapi-postgres/docker-compose.yml | 13 + fastapi-postgres/keploy/test-set-0/mocks.yaml | 1567 +++++++++++++++++ .../keploy/test-set-0/tests/test-1.yaml | 45 + .../keploy/test-set-0/tests/test-2.yaml | 58 + .../keploy/test-set-0/tests/test-3.yaml | 45 + .../keploy/test-set-0/tests/test-4.yaml | 45 + .../keploy/test-set-0/tests/test-5.yaml | 45 + .../keploy/test-set-0/tests/test-6.yaml | 45 + .../keploy/testReports/report-1.yaml | 519 ++++++ fastapi-postgres/requirements.txt | 37 + fastapi-postgres/sql/init.sql | 2 + 21 files changed, 2789 insertions(+) create mode 100644 fastapi-postgres/.gitignore create mode 100644 fastapi-postgres/Dockerfile create mode 100644 fastapi-postgres/README.md create mode 100644 fastapi-postgres/application/__init__.py create mode 100644 fastapi-postgres/application/crud.py create mode 100644 fastapi-postgres/application/database.py create mode 100644 fastapi-postgres/application/main.py create mode 100644 fastapi-postgres/application/models.py create mode 100644 fastapi-postgres/application/schemas.py create mode 100644 fastapi-postgres/data.json create mode 100644 fastapi-postgres/docker-compose.yml create mode 100755 fastapi-postgres/keploy/test-set-0/mocks.yaml create mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-1.yaml create mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-2.yaml create mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-3.yaml create mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-4.yaml create mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-5.yaml create mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-6.yaml create mode 100755 fastapi-postgres/keploy/testReports/report-1.yaml create mode 100644 fastapi-postgres/requirements.txt create mode 100644 fastapi-postgres/sql/init.sql diff --git a/fastapi-postgres/.gitignore b/fastapi-postgres/.gitignore new file mode 100644 index 0000000..78a1f19 --- /dev/null +++ b/fastapi-postgres/.gitignore @@ -0,0 +1,2 @@ +venv +application/__pycache__ \ No newline at end of file diff --git a/fastapi-postgres/Dockerfile b/fastapi-postgres/Dockerfile new file mode 100644 index 0000000..8dfa645 --- /dev/null +++ b/fastapi-postgres/Dockerfile @@ -0,0 +1,30 @@ +# Use the official Python image as the base image +FROM python:3.11.5-bullseye + +# Set the working directory to /app +WORKDIR /app + +# Copy the requirements file into the container +COPY requirements.txt . + +# Install the dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the rest of the application code into the container +COPY . . + +# Set environment variables for PostgreSQL +ENV POSTGRES_USER=postgres \ + POSTGRES_PASSWORD=postgres \ + POSTGRES_DB=studentdb \ + POSTGRES_HOST=0.0.0.0 \ + POSTGRES_PORT=5432 + +# Install PostgreSQL client +RUN apt-get update && apt-get install -y postgresql-client + +# Expose port 80 for the FastAPI application +EXPOSE 8000 + +# Start the FastAPI application +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/fastapi-postgres/README.md b/fastapi-postgres/README.md new file mode 100644 index 0000000..888804d --- /dev/null +++ b/fastapi-postgres/README.md @@ -0,0 +1,124 @@ +# FastAPI-Postgres CRUD Application + +A sample user data CRUD app to test Keploy integration capabilities using [FastAPI](https://fastapi.tiangolo.com/) and [PostgreSQL](https://www.postgresql.org/).
+Make the following requests to the respective endpoints - + +1. `GET students/` - Get all students. +2. `GET students/{id}` - Get a student by id. +3. `POST students/` - Create a student. +4. `PUT students/{id}` - Update a student by id. +5. `DELETE students/{id}` - Delete a student by id. + +## Installation Setup + +```bash +git clone https://github.com/keploy/samples-python.git && cd samples-python/fastapi-postgres +pip3 install -r requirements.txt +``` + +## Installation Keploy + +Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release + +**1. AMD Architecture** + +```shell +curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp + +sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +``` + +
+ 2. ARM Architecture + +```shell +curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_arm64.tar.gz" | tar xz -C /tmp + +sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +``` + +
+ +### Starting the PostgreSQL Instance + +```bash +# Start the application +docker-compose up -d +``` + +### Capture the Testcases + +This command will start the recording of API calls using ebpf:- + +```shell +sudo -E keploy record -c "uvicorn application.main:app --reload" +``` + +Make API Calls using Hoppscotch, Postman or cURL command. Keploy with capture those calls to generate the test-suites containing testcases and data mocks. + +### Make a POST request + +```bash +curl --location 'http://127.0.0.1:8000/students/' \ +--header 'Content-Type: application/json' \ +--data-raw '{ + "name": "Eva White", + "email": "evawhite@example.com", + "password": "evawhite111" + }' +``` + +```bash +curl --location 'http://127.0.0.1:8000/students/' \ +--header 'Content-Type: application/json' \ +--data-raw ' { + "name": "John Doe", + "email": "johndoe@example.com", + "password": "johndoe123" + }' +``` + +### Make a GET request to get all the data + +```bash +curl --location 'http://127.0.0.1:8000/students/' +``` + +This will return all the data saved in the database. + +### Make a GET request to get a specific data + +```bash +curl --location 'http://127.0.0.1:8000/students/1' +``` + +### Make a PUT request to update a specific data + +```bash +curl --location --request PUT 'http://127.0.0.1:8000/students/2' \ +--header 'Content-Type: application/json' \ +--data-raw ' { + "name": "John Dow", + "email": "doe.john@example.com", + "password": "johndoe123", + "stream": "Arts" + }' +``` + +### Make a DELETE request to delete a specific data + +```bash +curl --location --request DELETE 'http://127.0.0.1:8000/students/1' +``` + +Now all these API calls were captured as **editable** testcases and written to `keploy/tests` folder. The keploy directory would also have `mocks` file that contains all the outputs of postgres operations. + +## Run the Testcases + +Now let's run the application in test mode. + +```shell +sudo -E keploy test -c "uvicorn application.main:app --reload" --delay 10 +``` + +So, no need to setup fake database/apis like Postgres or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Postgres 😄** diff --git a/fastapi-postgres/application/__init__.py b/fastapi-postgres/application/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/fastapi-postgres/application/crud.py b/fastapi-postgres/application/crud.py new file mode 100644 index 0000000..ae0411e --- /dev/null +++ b/fastapi-postgres/application/crud.py @@ -0,0 +1,52 @@ +from sqlalchemy.orm import Session +from . import models, schemas + + +def get_student(db: Session, student_id: int): + return db.query(models.Student).filter(models.Student.id == student_id).first() + + +def get_student_byEmail(db: Session, student_email: str): + return db.query(models.Student).filter(models.Student.email == student_email).first() + + +def get_students(db: Session, skip: int = 0, limit: int = 50): + return db.query(models.Student).offset(skip).limit(limit).all() + + +def create_student(db: Session, student: schemas.StudentCreate): + student_hashed_password = password_hasher(student.password) + + db_student = models.Student(name=student.name, email=student.email, password=student_hashed_password) + db.add(db_student) + db.commit() + db.refresh(db_student) + return db_student + + +def update_student(db: Session, student: schemas.StudentUpdate, student_id: int): + student_old = db.query(models.Student).filter(models.Student.id == student_id).first() + if student_old is None: + return None + student_old.name = student_old.name if student.name is None else student.name + student_old.email = student_old.email if student.email is None else student.email + student_old.stream = student_old.stream if student.stream is None else student.stream + student_old.password = password_hasher(student.password) + db.commit() + db.refresh(student_old) + return student_old + + +def delete_student(db: Session, student_id: int): + student = db.query(models.Student).filter(models.Student.id == student_id).first() + if student: + db.delete(student) + db.commit() + return student + + +def password_hasher(password) -> str: + hashed_password = 's' + for i in range(0, len(password)): + hashed_password += chr(ord(password[i]) + 1) + return hashed_password diff --git a/fastapi-postgres/application/database.py b/fastapi-postgres/application/database.py new file mode 100644 index 0000000..044ffb7 --- /dev/null +++ b/fastapi-postgres/application/database.py @@ -0,0 +1,11 @@ +from sqlalchemy import create_engine +from sqlalchemy.ext.declarative import declarative_base +from sqlalchemy.orm import sessionmaker + + +SQLALCHEMY_DATABASE_URL = "postgresql://postgres:postgres@0.0.0.0:5432/studentdb" + +engine = create_engine(SQLALCHEMY_DATABASE_URL) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +Base = declarative_base() \ No newline at end of file diff --git a/fastapi-postgres/application/main.py b/fastapi-postgres/application/main.py new file mode 100644 index 0000000..294ad02 --- /dev/null +++ b/fastapi-postgres/application/main.py @@ -0,0 +1,59 @@ +from fastapi import Depends, FastAPI, HTTPException +from sqlalchemy.orm import Session + +from . import models, crud, schemas +from .database import SessionLocal, engine + +models.Base.metadata.create_all(bind=engine) + +app = FastAPI() + + +# Dependency +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() + + +@app.post('/students/', response_model=schemas.Student) +def create_student(student: schemas.StudentCreate, db: Session = Depends(get_db)): + db_student = crud.get_student_byEmail(db, student_email=student.email) + if db_student: + raise HTTPException(status_code=400, detail="Student already registered!!") + data = crud.create_student(db, student=student) + return data + + +@app.get('/students/', response_model=list[schemas.Student]) +def read_students(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): + students = crud.get_students(db, skip, limit) + if students == []: + raise HTTPException(404, 'Data not found!!') + return students + + +@app.get('/students/{student_id}', response_model=schemas.Student) +def read_student(student_id: int, db: Session = Depends(get_db)): + student = crud.get_student(db, student_id=student_id) + if student is None: + raise HTTPException(status_code=404, detail=f'Student with ID={student_id} not found!!') + return student + + +@app.put('/students/{student_id}', response_model=schemas.Student) +def update_student(student_id: int, student: schemas.StudentUpdate, db: Session = Depends(get_db)): + student = crud.update_student(db, student=student, student_id=student_id) + if student is None: + raise HTTPException(status_code=404, detail=f'Student with ID={student_id} not found!!') + return student + + +@app.delete('/students/{student_id}', response_model=schemas.Student) +def delete_student(student_id: int, db: Session = Depends(get_db)): + student = crud.delete_student(db, student_id=student_id) + if student is None: + raise HTTPException(status_code=404, detail=f'Student with ID={student_id} not found!!') + return student diff --git a/fastapi-postgres/application/models.py b/fastapi-postgres/application/models.py new file mode 100644 index 0000000..05dd1eb --- /dev/null +++ b/fastapi-postgres/application/models.py @@ -0,0 +1,13 @@ +from sqlalchemy import Integer, String, Column + +from .database import Base + + +class Student(Base): + __tablename__="students" + + id = Column(Integer, name="ID", primary_key=True, index=True, info="Stores the id of a student", autoincrement="auto") + name = Column(String, name="Name") + email = Column(String, name="Email", index=True) + password = Column(String, name="Hashed Password") + stream = Column(String, name="Subject Stream", default="Mathematics") diff --git a/fastapi-postgres/application/schemas.py b/fastapi-postgres/application/schemas.py new file mode 100644 index 0000000..2935dcb --- /dev/null +++ b/fastapi-postgres/application/schemas.py @@ -0,0 +1,24 @@ +from pydantic import BaseModel + + +class StudentBase(BaseModel): + name: str + email: str + + +class StudentCreate(StudentBase): + password: str + + +class StudentUpdate(StudentCreate): + stream: str + + class Config: + from_attributes = True + + +class Student(StudentUpdate): + id: int + + class Config: + from_attributes = True diff --git a/fastapi-postgres/data.json b/fastapi-postgres/data.json new file mode 100644 index 0000000..629467e --- /dev/null +++ b/fastapi-postgres/data.json @@ -0,0 +1,53 @@ +[ + { + "name": "John Doe", + "email": "johndoe@example.com", + "password": "johndoe123" + }, + { + "name": "Alice Smith", + "email": "alicesmith@example.com", + "password": "alicesmith789" + }, + { + "name": "Bob Johnson", + "email": "bobjohnson@example.com", + "password": "bobjohnson456" + }, + { + "name": "Eva White", + "email": "evawhite@example.com", + "password": "evawhite111" + }, + { + "name": "Michael Brown", + "email": "michaelbrown@example.com", + "password": "michaelbrown999" + }, + { + "name": "Sophia Lee", + "email": "sophialee@example.com", + "password": "sophialee777" + }, + { + "name": "David Hall", + "email": "davidhall@example.com", + "password": "davidhall222" + }, + { + "name": "Emma Turner", + "email": "emmaturner@example.com", + "password": "emmaturner654" + }, + { + "name": "Oliver Harris", + "email": "oliverharris@example.com", + "password": "oliverharris333" + }, + { + "name": "Ava Martinez", + "email": "avamartinez@example.com", + "password": "avamartinez888" + } + ] + \ No newline at end of file diff --git a/fastapi-postgres/docker-compose.yml b/fastapi-postgres/docker-compose.yml new file mode 100644 index 0000000..8cffd1a --- /dev/null +++ b/fastapi-postgres/docker-compose.yml @@ -0,0 +1,13 @@ +version: '3' +services: + + postgres: + image: postgres:latest + environment: + POSTGRES_DB: studentdb + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + ports: + - "5432:5432" # Map the PostgreSQL port to the host machine + volumes: + - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql diff --git a/fastapi-postgres/keploy/test-set-0/mocks.yaml b/fastapi-postgres/keploy/test-set-0/mocks.yaml new file mode 100755 index 0000000..e1a173b --- /dev/null +++ b/fastapi-postgres/keploy/test-set-0/mocks.yaml @@ -0,0 +1,1567 @@ +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - identifier: StartupRequest + payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl: + auth_mechanisms: + - SCRAM-SHA-256 + msg_type: 82 + auth_type: 10 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + password_message: + password: SCRAM-SHA-256 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_continue: {data: [114, 61, 52, 74, 86, 106, 122, 74, 112, 52, 47, 119, 114, 53, 76, 107, 84, 51, 47, 80, 100, 82, 122, 65, 109, 99, 112, 117, 117, 82, 118, 49, 67, 99, 87, 86, 114, 102, 122, 72, 79, 51, 51, 82, 105, 77, 105, 105, 52, 98, 44, 115, 61, 66, 89, 47, 121, 78, 51, 75, 102, 49, 117, 90, 109, 90, 69, 100, 85, 72, 111, 68, 105, 117, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} + msg_type: 82 + auth_type: 11 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_final: {data: [118, 61, 84, 87, 72, 57, 77, 119, 88, 70, 57, 109, 51, 107, 113, 85, 71, 76, 56, 110, 52, 104, 43, 97, 50, 106, 83, 89, 55, 74, 53, 109, 97, 122, 75, 111, 77, 83, 51, 52, 53, 75, 89, 80, 107, 61]} + backend_key_data: + process_id: 33 + secret_key: 4106888949 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Etc/UTC + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "on" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: postgres + - name: client_encoding + value: UTF8 + - name: server_version + value: 16.0 (Debian 16.0-1.pgdg120+1) + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: | + SELECT t.oid, typarray + FROM pg_type t JOIN pg_namespace ns + ON typnamespace = ns.oid + WHERE typname = 'hstore'; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [111, 105, 100], table_oid: 1247, table_attribute_number: 1, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}, {name: [116, 121, 112, 97, 114, 114, 97, 121], table_oid: 1247, table_attribute_number: 15, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select pg_catalog.version() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{values: [[80, 111, 115, 116, 103, 114, 101, 83, 81, 76, 32, 49, 54, 46, 48, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 54, 46, 48, 45, 49, 46, 112, 103, 100, 103, 49, 50, 48, 43, 49, 41, 32, 111, 110, 32, 120, 56, 54, 95, 54, 52, 45, 112, 99, 45, 108, 105, 110, 117, 120, 45, 103, 110, 117, 44, 32, 99, 111, 109, 112, 105, 108, 101, 100, 32, 98, 121, 32, 103, 99, 99, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 50, 46, 50, 46, 48, 45, 49, 52, 41, 32, 49, 50, 46, 50, 46, 48, 44, 32, 54, 52, 45, 98, 105, 116]]}, {values: [[80, 111, 115, 116, 103, 114, 101, 83, 81, 76, 32, 49, 54, 46, 48, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 54, 46, 48, 45, 49, 46, 112, 103, 100, 103, 49, 50, 48, 43, 49, 41, 32, 111, 110, 32, 120, 56, 54, 95, 54, 52, 45, 112, 99, 45, 108, 105, 110, 117, 120, 45, 103, 110, 117, 44, 32, 99, 111, 109, 112, 105, 108, 101, 100, 32, 98, 121, 32, 103, 99, 99, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 50, 46, 50, 46, 48, 45, 49, 52, 41, 32, 49, 50, 46, 50, 46, 48, 44, 32, 54, 52, 45, 98, 105, 116]]}, {values: [[80, 111, 115, 116, 103, 114, 101, 83, 81, 76, 32, 49, 54, 46, 48, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 54, 46, 48, 45, 49, 46, 112, 103, 100, 103, 49, 50, 48, 43, 49, 41, 32, 111, 110, 32, 120, 56, 54, 95, 54, 52, 45, 112, 99, 45, 108, 105, 110, 117, 120, 45, 103, 110, 117, 44, 32, 99, 111, 109, 112, 105, 108, 101, 100, 32, 98, 121, 32, 103, 99, 99, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 50, 46, 50, 46, 48, 45, 49, 52, 41, 32, 49, 50, 46, 50, 46, 48, 44, 32, 54, 52, 45, 98, 105, 116]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [118, 101, 114, 115, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select current_schema() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{values: [[112, 117, 98, 108, 105, 99]]}, {values: [[112, 117, 98, 108, 105, 99]]}, {values: [[112, 117, 98, 108, 105, 99]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [99, 117, 114, 114, 101, 110, 116, 95, 115, 99, 104, 101, 109, 97], table_oid: 0, table_attribute_number: 0, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show transaction isolation level + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 72 + - 79 + - 87 + data_row: [{values: [[114, 101, 97, 100, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100]]}, {values: [[114, 101, 97, 100, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100]]}, {values: [[114, 101, 97, 100, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 95, 105, 115, 111, 108, 97, 116, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show standard_conforming_strings + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 72 + - 79 + - 87 + data_row: [{values: [[111, 110]]}, {values: [[111, 110]]}, {values: [[111, 110]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 97, 110, 100, 97, 114, 100, 95, 99, 111, 110, 102, 111, 114, 109, 105, 110, 103, 95, 115, 116, 114, 105, 110, 103, 115], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT pg_catalog.pg_class.relname \nFROM pg_catalog.pg_class JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.oid = pg_catalog.pg_class.relnamespace \nWHERE pg_catalog.pg_class.relname = 'students' AND pg_catalog.pg_class.relkind = ANY (ARRAY['r', 'p', 'f', 'v', 'm']) AND pg_catalog.pg_table_is_visible(pg_catalog.pg_class.oid) AND pg_catalog.pg_namespace.nspname != 'pg_catalog'" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{values: [[115, 116, 117, 100, 101, 110, 116, 115]]}, {values: [[115, 116, 117, 100, 101, 110, 116, 115]]}, {values: [[115, 116, 117, 100, 101, 110, 116, 115]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [114, 101, 108, 110, 97, 109, 101], table_oid: 1259, table_attribute_number: 2, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \n LIMIT 100 OFFSET 0" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"Email\" = 'michaelbrown@example.com' \n LIMIT 1" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('Michael Brown', 'michaelbrown@example.com', 'snjdibfmcspxo:::', 'Mathematics') RETURNING students."ID" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 73 + - 78 + - 83 + - 69 + - 82 + - 84 + - 32 + - 48 + - 32 + - 49 + data_row: [{values: [[49]]}, {values: [[49]]}, {values: [[49]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT students.\"ID\", students.\"Name\", students.\"Email\", students.\"Hashed Password\", students.\"Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 1" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 11 \n LIMIT 1" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 1 \n LIMIT 1" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \n LIMIT 100 OFFSET 0" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 1 \n LIMIT 1" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: DELETE FROM students WHERE students."ID" = 1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 68 + - 69 + - 76 + - 69 + - 84 + - 69 + - 32 + - 49 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - identifier: StartupRequest + payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl: + auth_mechanisms: + - SCRAM-SHA-256 + msg_type: 82 + auth_type: 10 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + password_message: + password: SCRAM-SHA-256 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_continue: {data: [114, 61, 104, 65, 52, 72, 75, 114, 50, 75, 103, 51, 111, 66, 110, 76, 108, 120, 97, 78, 113, 50, 51, 110, 97, 97, 49, 113, 98, 70, 100, 86, 48, 121, 86, 51, 115, 113, 116, 87, 116, 108, 115, 54, 73, 51, 97, 117, 83, 110, 44, 115, 61, 87, 115, 114, 48, 101, 50, 78, 57, 105, 51, 55, 51, 89, 121, 78, 105, 47, 53, 120, 100, 86, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} + msg_type: 82 + auth_type: 11 +--- +version: api.keploy.io/v1beta2 +kind: Postgres +name: mocks +spec: + metadata: {} + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_final: {data: [118, 61, 48, 107, 114, 111, 101, 115, 78, 107, 115, 108, 107, 101, 51, 100, 75, 77, 79, 85, 109, 100, 78, 57, 88, 71, 103, 78, 87, 47, 89, 118, 114, 122, 105, 80, 85, 67, 43, 71, 114, 65, 53, 47, 56, 61]} + backend_key_data: + process_id: 54 + secret_key: 1374794602 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Etc/UTC + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "on" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: postgres + - name: client_encoding + value: UTF8 + - name: server_version + value: 16.0 (Debian 16.0-1.pgdg120+1) + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 \ No newline at end of file diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-1.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-1.yaml new file mode 100755 index 0000000..df8342b --- /dev/null +++ b/fastapi-postgres/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,45 @@ +version: api.keploy.io/v1beta2 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: 1d33acb6-386d-45d1-99db-52329895a032 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 404 + header: + Content-Length: "29" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:02 GMT + Server: uvicorn + body: '{"detail":"Data not found!!"}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + objects: [] + assertions: + noise: + - header.Date + created: 1697621766 +curl: | + curl --request GET \ + --url http://127.0.0.1:8000/students/ \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'User-Agent: PostmanRuntime/7.33.0' \ + --header 'Accept: */*' \ + --header 'Postman-Token: 1d33acb6-386d-45d1-99db-52329895a032' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-2.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-2.yaml new file mode 100755 index 0000000..810598c --- /dev/null +++ b/fastapi-postgres/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,58 @@ +version: api.keploy.io/v1beta2 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "121" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: aba3841e-82f1-489f-9dda-c1c3e3ef3979 + User-Agent: PostmanRuntime/7.33.0 + body: |4- + { + "name": "Michael Brown", + "email": "michaelbrown@example.com", + "password": "michaelbrown999" + } + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "119" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:07 GMT + Server: uvicorn + body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + objects: [] + assertions: + noise: + - header.Date + created: 1697621770 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/students/ \ + --header 'User-Agent: PostmanRuntime/7.33.0' \ + --header 'Accept: */*' \ + --header 'Postman-Token: aba3841e-82f1-489f-9dda-c1c3e3ef3979' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'Content-Type: application/json' \ + --data ' { + "name": "Michael Brown", + "email": "michaelbrown@example.com", + "password": "michaelbrown999" + }' diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-3.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-3.yaml new file mode 100755 index 0000000..ac81f63 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,45 @@ +version: api.keploy.io/v1beta2 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/11 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: 4c94cd86-3b39-4fe6-ba34-df66b82fd932 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 404 + header: + Content-Length: "43" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:21 GMT + Server: uvicorn + body: '{"detail":"Student with ID=11 not found!!"}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + objects: [] + assertions: + noise: + - header.Date + created: 1697621784 +curl: | + curl --request GET \ + --url http://127.0.0.1:8000/students/11 \ + --header 'Postman-Token: 4c94cd86-3b39-4fe6-ba34-df66b82fd932' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'User-Agent: PostmanRuntime/7.33.0' \ + --header 'Accept: */*' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-4.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-4.yaml new file mode 100755 index 0000000..2abb599 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-0/tests/test-4.yaml @@ -0,0 +1,45 @@ +version: api.keploy.io/v1beta2 +kind: Http +name: test-4 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/1 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: b46c5b40-375c-4956-bcea-84ef922f77f4 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "119" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:25 GMT + Server: uvicorn + body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + objects: [] + assertions: + noise: + - header.Date + created: 1697621789 +curl: | + curl --request GET \ + --url http://127.0.0.1:8000/students/1 \ + --header 'User-Agent: PostmanRuntime/7.33.0' \ + --header 'Accept: */*' \ + --header 'Postman-Token: b46c5b40-375c-4956-bcea-84ef922f77f4' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-5.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-5.yaml new file mode 100755 index 0000000..dab53d3 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-0/tests/test-5.yaml @@ -0,0 +1,45 @@ +version: api.keploy.io/v1beta2 +kind: Http +name: test-5 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: cdbe1654-026d-4eaa-a059-1f6374a0c4c7 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "121" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:31 GMT + Server: uvicorn + body: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + objects: [] + assertions: + noise: + - header.Date + created: 1697621794 +curl: | + curl --request GET \ + --url http://127.0.0.1:8000/students/ \ + --header 'User-Agent: PostmanRuntime/7.33.0' \ + --header 'Accept: */*' \ + --header 'Postman-Token: cdbe1654-026d-4eaa-a059-1f6374a0c4c7' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-6.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-6.yaml new file mode 100755 index 0000000..c378e76 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-0/tests/test-6.yaml @@ -0,0 +1,45 @@ +version: api.keploy.io/v1beta2 +kind: Http +name: test-6 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/1 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: 4eb76f24-2797-486e-bfda-188164f4611e + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "119" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:38 GMT + Server: uvicorn + body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + objects: [] + assertions: + noise: + - header.Date + created: 1697621802 +curl: | + curl --request DELETE \ + --url http://127.0.0.1:8000/students/1 \ + --header 'Postman-Token: 4eb76f24-2797-486e-bfda-188164f4611e' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'User-Agent: PostmanRuntime/7.33.0' \ + --header 'Accept: */*' \ diff --git a/fastapi-postgres/keploy/testReports/report-1.yaml b/fastapi-postgres/keploy/testReports/report-1.yaml new file mode 100755 index 0000000..6ec8809 --- /dev/null +++ b/fastapi-postgres/keploy/testReports/report-1.yaml @@ -0,0 +1,519 @@ +version: api.keploy.io/v1beta1 +name: report-21 +status: PASSED +success: 6 +failure: 0 +total: 6 +tests: + - kind: Http + name: report-21 + status: PASSED + started: 1697621960 + completed: 1697621960 + test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 + mock_path: "" + test_case_id: test-1 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: 1d33acb6-386d-45d1-99db-52329895a032 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 404 + header: + Content-Length: "29" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:02 GMT + Server: uvicorn + body: '{"detail":"Data not found!!"}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + noise: + - header.Date + result: + status_code: + normal: true + expected: 404 + actual: 404 + headers_result: + - normal: true + expected: + key: Content-Length + value: + - "29" + actual: + key: Content-Length + value: + - "29" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Wed, 18 Oct 2023 09:36:02 GMT + actual: + key: Date + value: + - Wed, 18 Oct 2023 09:39:19 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + body_result: + - normal: true + type: JSON + expected: '{"detail":"Data not found!!"}' + actual: '{"detail":"Data not found!!"}' + dep_result: [] + - kind: Http + name: report-21 + status: PASSED + started: 1697621960 + completed: 1697621960 + test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 + mock_path: "" + test_case_id: test-2 + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "121" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: aba3841e-82f1-489f-9dda-c1c3e3ef3979 + User-Agent: PostmanRuntime/7.33.0 + body: |4- + { + "name": "Michael Brown", + "email": "michaelbrown@example.com", + "password": "michaelbrown999" + } + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "119" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:07 GMT + Server: uvicorn + body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + noise: + - header.Date + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Length + value: + - "119" + actual: + key: Content-Length + value: + - "119" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Wed, 18 Oct 2023 09:36:07 GMT + actual: + key: Date + value: + - Wed, 18 Oct 2023 09:39:19 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + body_result: + - normal: true + type: JSON + expected: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + actual: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + dep_result: [] + - kind: Http + name: report-21 + status: PASSED + started: 1697621960 + completed: 1697621960 + test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 + mock_path: "" + test_case_id: test-3 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/11 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: 4c94cd86-3b39-4fe6-ba34-df66b82fd932 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 404 + header: + Content-Length: "43" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:21 GMT + Server: uvicorn + body: '{"detail":"Student with ID=11 not found!!"}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + noise: + - header.Date + result: + status_code: + normal: true + expected: 404 + actual: 404 + headers_result: + - normal: true + expected: + key: Content-Length + value: + - "43" + actual: + key: Content-Length + value: + - "43" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Wed, 18 Oct 2023 09:36:21 GMT + actual: + key: Date + value: + - Wed, 18 Oct 2023 09:39:20 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + body_result: + - normal: true + type: JSON + expected: '{"detail":"Student with ID=11 not found!!"}' + actual: '{"detail":"Student with ID=11 not found!!"}' + dep_result: [] + - kind: Http + name: report-21 + status: PASSED + started: 1697621960 + completed: 1697621960 + test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 + mock_path: "" + test_case_id: test-4 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/1 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: b46c5b40-375c-4956-bcea-84ef922f77f4 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "119" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:25 GMT + Server: uvicorn + body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + noise: + - header.Date + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Length + value: + - "119" + actual: + key: Content-Length + value: + - "119" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Wed, 18 Oct 2023 09:36:25 GMT + actual: + key: Date + value: + - Wed, 18 Oct 2023 09:39:20 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + body_result: + - normal: true + type: JSON + expected: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + actual: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + dep_result: [] + - kind: Http + name: report-21 + status: PASSED + started: 1697621960 + completed: 1697621960 + test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 + mock_path: "" + test_case_id: test-5 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: cdbe1654-026d-4eaa-a059-1f6374a0c4c7 + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "121" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:31 GMT + Server: uvicorn + body: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + noise: + - header.Date + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Date + value: + - Wed, 18 Oct 2023 09:36:31 GMT + actual: + key: Date + value: + - Wed, 18 Oct 2023 09:39:20 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + - normal: true + expected: + key: Content-Length + value: + - "121" + actual: + key: Content-Length + value: + - "121" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + body_result: + - normal: true + type: JSON + expected: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' + actual: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' + dep_result: [] + - kind: Http + name: report-21 + status: PASSED + started: 1697621960 + completed: 1697621960 + test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 + mock_path: "" + test_case_id: test-6 + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/1 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Host: 127.0.0.1:8000 + Postman-Token: 4eb76f24-2797-486e-bfda-188164f4611e + User-Agent: PostmanRuntime/7.33.0 + body: "" + body_type: "" + resp: + status_code: 200 + header: + Content-Length: "119" + Content-Type: application/json + Date: Wed, 18 Oct 2023 09:36:38 GMT + Server: uvicorn + body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + noise: + - header.Date + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Wed, 18 Oct 2023 09:36:38 GMT + actual: + key: Date + value: + - Wed, 18 Oct 2023 09:39:20 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + - normal: true + expected: + key: Content-Length + value: + - "119" + actual: + key: Content-Length + value: + - "119" + body_result: + - normal: true + type: JSON + expected: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + actual: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' + dep_result: [] +test_set: test-set-3 diff --git a/fastapi-postgres/requirements.txt b/fastapi-postgres/requirements.txt new file mode 100644 index 0000000..946ca50 --- /dev/null +++ b/fastapi-postgres/requirements.txt @@ -0,0 +1,37 @@ +annotated-types==0.6.0 +anyio==3.7.1 +certifi==2023.7.22 +click==8.1.7 +dnspython==2.4.2 +email-validator==2.0.0.post2 +exceptiongroup==1.1.3 +fastapi==0.103.2 +greenlet==3.0.0 +h11==0.14.0 +httpcore==0.18.0 +httptools==0.6.0 +httpx==0.25.0 +idna==3.4 +itsdangerous==2.1.2 +Jinja2==3.1.2 +MarkupSafe==2.1.3 +orjson==3.9.8 +psycopg2==2.9.9 +psycopg2-binary==2.9.9 +pydantic==2.4.2 +pydantic-extra-types==2.1.0 +pydantic-settings==2.0.3 +pydantic_core==2.10.1 +pyscopg2==66.0.2 +python-dotenv==1.0.0 +python-multipart==0.0.6 +PyYAML==6.0.1 +sniffio==1.3.0 +SQLAlchemy==2.0.21 +starlette==0.27.0 +typing_extensions==4.8.0 +ujson==5.8.0 +uvicorn==0.23.2 +uvloop==0.17.0 +watchfiles==0.20.0 +websockets==11.0.3 \ No newline at end of file diff --git a/fastapi-postgres/sql/init.sql b/fastapi-postgres/sql/init.sql new file mode 100644 index 0000000..aaa55f3 --- /dev/null +++ b/fastapi-postgres/sql/init.sql @@ -0,0 +1,2 @@ +DROP DATABASE studentdb IF EXISTS; +CREATE DATABASE studentdb; \ No newline at end of file From a4f811eb46a0e7738d3e34072ec00b469b566238 Mon Sep 17 00:00:00 2001 From: Shashwat Gupta Date: Sat, 28 Oct 2023 07:48:43 +0530 Subject: [PATCH 03/31] feat: application description added to the master readme * fix: removed the docker part from readme Signed-off-by: Shashwat79802 * fix: master readme updated Signed-off-by: Shashwat79802 * feat: application description added to the master readme Signed-off-by: Shashwat79802 --------- Signed-off-by: Shashwat79802 --- README | 1 - README.md | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) delete mode 100644 README create mode 100644 README.md diff --git a/README b/README deleted file mode 100644 index 5165170..0000000 --- a/README +++ /dev/null @@ -1 +0,0 @@ -Sample Applications to try Keploy with Python Applications using external dependencies like MongoDB. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c4e8a23 --- /dev/null +++ b/README.md @@ -0,0 +1,32 @@ +

Keploy x Python Sample Applications

+

+ + + + +

+ +This repo contains the samples for [Keploy's](https://keploy.io) Python-based Application. Please feel free to contribute if you'd like submit a sample for another use-case or library. + +>**Note** :- Issue Creation is disabled on this Repository, please visit [here](https://github.com/keploy/keploy/issues/new/choose) to submit Issue. + + +## Sample Apps with Keploy + +1. [Flask-Mongo](https://github.com/keploy/samples-python/tree/main/flask-mongo) - This application is a simple student management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. + +2. [Django-Postgres](https://github.com/keploy/samples-python/tree/main/django-postgres) - This is an application to perform basic CRUD (Create, Read, Update, Delete) operations on user records built using Python's Django framework and PostgreSQL for data storage. + +3. [FastAPI-Postgres](https://github.com/keploy/samples-python/tree/main/fastapi-postgres) - This application is a student management API built using Python's FastAPI and PostgreSQL for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student data. + +## Community Support ❤️ + +We'd love to collaborate with you to make Keploy great. To get started: +* [Slack](https://join.slack.com/t/keploy/shared_invite/zt-12rfbvc01-o54cOG0X1G6eVJTuI_orSA) - Discussions with the community and the team. +* [GitHub](https://github.com/keploy/keploy/issues) - For bug reports and feature requests. + +[![Generic badge](https://img.shields.io/badge/Slack-teal.svg?style=for-the-badge)](https://join.slack.com/t/keploy/shared_invite/zt-12rfbvc01-o54cOG0X1G6eVJTuI_orSA) +[![Generic badge](https://img.shields.io/badge/LinkedIn-blue.svg?style=for-the-badge)](https://www.linkedin.com/company/keploy/) +[![Generic badge](https://img.shields.io/badge/Youtube-teal.svg?style=for-the-badge)](https://www.youtube.com/channel/UC6OTg7F4o0WkmNtSoob34lg) +[![Generic badge](https://img.shields.io/badge/Twitter-blue.svg?style=for-the-badge)](https://twitter.com/Keployio) +[![Generic badge](https://img.shields.io/badge/Documentation-teal.svg?style=for-the-badge)](https://keploy.io/docs/) From fc9acbd36edaf6d8d9ed35166f1c07491a671ddc Mon Sep 17 00:00:00 2001 From: Shashwat79802 Date: Tue, 14 Nov 2023 15:29:58 +0530 Subject: [PATCH 04/31] feat: adding new python sample app Signed-off-by: Shashwat79802 --- README.md | 2 + fastapi-twilio/.gitignore | 2 + fastapi-twilio/Dockerfile | 11 + fastapi-twilio/README.md | 84 ++++++ fastapi-twilio/keploy-config.yaml | 64 ++++ fastapi-twilio/keploy/test-set-0/mocks.yaml | 162 ++++++++++ .../keploy/test-set-0/tests/test-1.yaml | 58 ++++ .../keploy/test-set-0/tests/test-2.yaml | 58 ++++ .../keploy/test-set-0/tests/test-3.yaml | 58 ++++ .../keploy/testReports/report-1.yaml | 284 ++++++++++++++++++ fastapi-twilio/main.py | 39 +++ fastapi-twilio/requirements.txt | 28 ++ 12 files changed, 850 insertions(+) create mode 100644 fastapi-twilio/.gitignore create mode 100644 fastapi-twilio/Dockerfile create mode 100644 fastapi-twilio/README.md create mode 100755 fastapi-twilio/keploy-config.yaml create mode 100755 fastapi-twilio/keploy/test-set-0/mocks.yaml create mode 100755 fastapi-twilio/keploy/test-set-0/tests/test-1.yaml create mode 100755 fastapi-twilio/keploy/test-set-0/tests/test-2.yaml create mode 100755 fastapi-twilio/keploy/test-set-0/tests/test-3.yaml create mode 100755 fastapi-twilio/keploy/testReports/report-1.yaml create mode 100644 fastapi-twilio/main.py create mode 100644 fastapi-twilio/requirements.txt diff --git a/README.md b/README.md index c4e8a23..d99979a 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ This repo contains the samples for [Keploy's](https://keploy.io) Python-based Ap 3. [FastAPI-Postgres](https://github.com/keploy/samples-python/tree/main/fastapi-postgres) - This application is a student management API built using Python's FastAPI and PostgreSQL for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student data. +4. [FastAPI-Twilio](https://github.com/keploy/samples-python/tree/main/fastapi-twilio) - This application is a SMS sending API built using Python's FastAPI and Twilio for their SMS sharing service. + ## Community Support ❤️ We'd love to collaborate with you to make Keploy great. To get started: diff --git a/fastapi-twilio/.gitignore b/fastapi-twilio/.gitignore new file mode 100644 index 0000000..bdd515a --- /dev/null +++ b/fastapi-twilio/.gitignore @@ -0,0 +1,2 @@ +./venv +./__pycache__ \ No newline at end of file diff --git a/fastapi-twilio/Dockerfile b/fastapi-twilio/Dockerfile new file mode 100644 index 0000000..e8aa5dd --- /dev/null +++ b/fastapi-twilio/Dockerfile @@ -0,0 +1,11 @@ +FROM python:3.11.5-bullseye + +WORKDIR /app + +COPY . /app/ + +RUN pip install --no-cache-dir --upgrade -r /app/requirements.txt + +EXPOSE 8000 + +CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/fastapi-twilio/README.md b/fastapi-twilio/README.md new file mode 100644 index 0000000..06bbc82 --- /dev/null +++ b/fastapi-twilio/README.md @@ -0,0 +1,84 @@ +# FastAPI-Twilio Application + +A sample FastAPI-Twilio app to test Keploy integration capabilities using [FastAPI](https://fastapi.tiangolo.com/) and [Twilio](https://www.twilio.com/en-us).
+ +## Installation Setup + +```bash +git clone https://github.com/keploy/samples-python.git && cd samples-python/fastapi-twilio +pip3 install -r requirements.txt +``` + +## Installation Keploy + +Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release + +**1. AMD Architecture** + +```shell +curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp + +sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +``` + +
+ 2. ARM Architecture + +```shell +curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_arm64.tar.gz" | tar xz -C /tmp + +sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +``` + +
+ +### Get your Twilio Credentials + +You can get your Twilio credentials by signing in to [Twilio Console](https://console.twilio.com/). +Once you get the Twilio Account SID, Auth Token, and Phone Number, modify the `.env` file with your credentials. + +### Capture the Testcases + +This command will start the recording of API calls:- + +```shell +keploy record -c "uvicorn main:app --reload" +``` + +Make API Calls using Hoppscotch, Postman or cURL command. Keploy with capture those calls to generate the test-suites containing testcases and data mocks. + +### Make the POST requests + +1. Replace the place holder below i.e. `YOUR_REGISTERED_PERSONAL_PHONE_NUMBER` with your registered personal phone number that you linked with Twilio. + + ```bash + curl --location 'http://127.0.0.1:8000/send-sms/' \ + --header 'Content-Type: application/json' \ + --data '{ + "Body": "Test, testtt, testttttttssss :)", + "To": "YOUR_REGISTERED_PERSONAL_PHONE_NUMBER", + }' + ``` + +2. Replace the place holder below i.e. `SOME_WRONG_PHONE_NUMBER` with any wrong phone number and make the request. + + ```bash + curl --location 'http://127.0.0.1:8000/send-sms/' \ + --header 'Content-Type: application/json' \ + --data '{ + "Body": "Test, testtt, testttttttssss :)", + "To": "SOME_WRONG_PHONE_NUMBER", + }' + ``` + +Now all these API calls were captured as **editable** testcases and written to `keploy/tests` folder. The keploy directory would also have `mocks` file that contains all the outputs of Twilio operations. + +## Run the Testcases + +Now let's run the application in test mode. + +```shell +keploy test -c "uvicorn main:app --reload" --delay 10 +``` + +So, no need to setup fake apis like Twilio or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Twilio 😄** diff --git a/fastapi-twilio/keploy-config.yaml b/fastapi-twilio/keploy-config.yaml new file mode 100755 index 0000000..c7e3e02 --- /dev/null +++ b/fastapi-twilio/keploy-config.yaml @@ -0,0 +1,64 @@ +record: + path: "" + # mandatory + command: "" + proxyport: 0 + containerName: "" + networkName: "" + delay: 5 + passThroughPorts: [] +test: + path: "" + # mandatory + command: "" + proxyport: 0 + containerName: "" + networkName: "" + testSets: [] + globalNoise: |- + { + "global": { + "body": {}, + "header": {} + }, + "test-sets": { + "test-set-name": { + "body": {}, + "header": {} + } + } + } + delay: 5 + apiTimeout: 5 + passThroughPorts: [] + # + # Example on using globalNoise + # globalNoise: |- + # { + # "global": { + # "body": { + # # to ignore some values for a field, + # # pass regex patterns to the corresponding array value + # "url": ["https?://\S+", "http://\S+"], + # }, + # "header": { + # # to ignore the entire field, pass an empty array + # "Date: [], + # } + # }, + # # to ignore fields or the corresponding values for a specific test-set, + # # pass the test-set-name as a key to the "test-sets" object and + # # populate the corresponding "body" and "header" objects + # "test-sets": { + # "test-set-1": { + # "body": { + # # ignore all the values for the "url" field + # "url": [] + # }, + # "header": { + # # we can also pass the exact value to ignore for a field + # "User-Agent": ["PostmanRuntime/7.34.0"] + # } + # } + # } + # } diff --git a/fastapi-twilio/keploy/test-set-0/mocks.yaml b/fastapi-twilio/keploy/test-set-0/mocks.yaml new file mode 100755 index 0000000..cd2a8bf --- /dev/null +++ b/fastapi-twilio/keploy/test-set-0/mocks.yaml @@ -0,0 +1,162 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: mocks +spec: + metadata: + name: Http + operation: POST + type: HTTP_CLIENT + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: /2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages.json + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate + Authorization: Basic QUMxOTQxMzY4N2Q5Y2UyOGM4MGNkYTk0NDczMGY4YjI4NjpjMTc0MDc5YzU2NTA0N2FmYWJmNDk5MWI2ZGQ1MmFiYg== + Connection: keep-alive + Content-Length: "82" + Content-Type: application/x-www-form-urlencoded + User-Agent: python-requests/2.31.0 + body: Body=Test%2C+testtt%2C+testttttttssss+%3A%29&From=%2B16413324066&To=%2B91700004379 + body_type: "" + timestamp: 0001-01-01T00:00:00Z + resp: + status_code: 400 + header: + Access-Control-Allow-Credentials: "true" + Access-Control-Allow-Headers: Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Idempotency-Key + Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS + Access-Control-Allow-Origin: '*' + Access-Control-Expose-Headers: ETag + Connection: keep-alive + Content-Length: 158,158 + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:26:29 GMT + Strict-Transport-Security: max-age=31536000 + Twilio-Concurrent-Requests: "1" + Twilio-Request-Duration: "0.051" + Twilio-Request-Id: RQec3c4676524fe2951583489e90bc1b33 + X-Api-Domain: api.twilio.com + X-Home-Region: us1 + X-Powered-By: AT-5000 + X-Shenanigans: none + body: '{"code": 21211, "message": "The ''To'' number +9170000XXXX is not a valid phone number", "more_info": "https://www.twilio.com/docs/errors/21211", "status": 400}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + objects: [] + created: 1699953989 + reqTimestampMock: 2023-11-14T14:56:28.791864295+05:30 + resTimestampMock: 2023-11-14T14:56:29.304057844+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Http +name: mocks +spec: + metadata: + name: Http + operation: POST + type: HTTP_CLIENT + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: /2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages.json + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate + Authorization: Basic QUMxOTQxMzY4N2Q5Y2UyOGM4MGNkYTk0NDczMGY4YjI4NjpjMTc0MDc5YzU2NTA0N2FmYWJmNDk5MWI2ZGQ1MmFiYg== + Connection: keep-alive + Content-Length: "83" + Content-Type: application/x-www-form-urlencoded + User-Agent: python-requests/2.31.0 + body: Body=Test%2C+testtt%2C+testttttttssss+%3A%29&From=%2B16413324066&To=%2B917000043797 + body_type: "" + timestamp: 0001-01-01T00:00:00Z + resp: + status_code: 201 + header: + Access-Control-Allow-Credentials: "true" + Access-Control-Allow-Headers: Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Idempotency-Key + Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS + Access-Control-Allow-Origin: '*' + Access-Control-Expose-Headers: ETag + Connection: keep-alive + Content-Length: 834,834 + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:26:35 GMT + Twilio-Concurrent-Requests: "1" + Twilio-Request-Duration: "0.131" + Twilio-Request-Id: RQ2f5288499581f3fe12524b11bbb3d866 + X-Api-Domain: api.twilio.com + X-Home-Region: us1 + X-Powered-By: AT-5000 + X-Shenanigans: none + body: '{"body": "Sent from your Twilio trial account - Test, testtt, testttttttssss :)", "num_segments": "1", "direction": "outbound-api", "from": "+16413324066", "date_updated": "Tue, 14 Nov 2023 09:26:35 +0000", "price": null, "error_message": null, "uri": "/2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages/SM2f5288499581f3fe12524b11bbb3d866.json", "account_sid": "AC19413687d9ce28c80cda944730f8b286", "num_media": "0", "to": "+917000043797", "date_created": "Tue, 14 Nov 2023 09:26:35 +0000", "status": "queued", "sid": "SM2f5288499581f3fe12524b11bbb3d866", "date_sent": null, "messaging_service_sid": null, "error_code": null, "price_unit": "USD", "api_version": "2010-04-01", "subresource_uris": {"media": "/2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages/SM2f5288499581f3fe12524b11bbb3d866/Media.json"}}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + objects: [] + created: 1699953995 + reqTimestampMock: 2023-11-14T14:56:34.833506359+05:30 + resTimestampMock: 2023-11-14T14:56:35.27188354+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Http +name: mocks +spec: + metadata: + name: Http + operation: POST + type: HTTP_CLIENT + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: /2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages.json + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate + Authorization: Basic QUMxOTQxMzY4N2Q5Y2UyOGM4MGNkYTk0NDczMGY4YjI4NjpjMTc0MDc5YzU2NTA0N2FmYWJmNDk5MWI2ZGQ1MmFiYg== + Connection: keep-alive + Content-Length: "81" + Content-Type: application/x-www-form-urlencoded + User-Agent: python-requests/2.31.0 + body: Body=Test%2C+testtt%2C+testttttttssss+%3A%29&From=%2B16413324066&To=%2B9170000437 + body_type: "" + timestamp: 0001-01-01T00:00:00Z + resp: + status_code: 400 + header: + Access-Control-Allow-Credentials: "true" + Access-Control-Allow-Headers: Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Idempotency-Key + Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS + Access-Control-Allow-Origin: '*' + Access-Control-Expose-Headers: ETag + Connection: keep-alive + Content-Length: 335,335 + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:27:21 GMT + Twilio-Concurrent-Requests: "1" + Twilio-Request-Duration: "0.080" + Twilio-Request-Id: RQb54d7f05d29e83bc89889cc136bcd99d + X-Api-Domain: api.twilio.com + X-Home-Region: us1 + X-Powered-By: AT-5000 + X-Shenanigans: none + body: '{"code": 21608, "message": "The number +917000XXXX is unverified. Trial accounts cannot send messages to unverified numbers; verify +917000XXXX at twilio.com/user/account/phone-numbers/verified, or purchase a Twilio number to send messages to unverified numbers", "more_info": "https://www.twilio.com/docs/errors/21608", "status": 400}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + objects: [] + created: 1699954041 + reqTimestampMock: 2023-11-14T14:57:20.914415283+05:30 + resTimestampMock: 2023-11-14T14:57:21.298027703+05:30 diff --git a/fastapi-twilio/keploy/test-set-0/tests/test-1.yaml b/fastapi-twilio/keploy/test-set-0/tests/test-1.yaml new file mode 100755 index 0000000..c088b98 --- /dev/null +++ b/fastapi-twilio/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,58 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/send-sms/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "75" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: c871b715-7aae-46b6-8e0d-1341aa426624 + User-Agent: PostmanRuntime/7.34.0 + body: |- + { + "Body": "Test, testtt, testttttttssss :)", + "To": "+91700004379" + } + body_type: "" + timestamp: 2023-11-14T14:56:25.800517709+05:30 + resp: + status_code: 200 + header: + Content-Length: "73" + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:26:25 GMT + Server: uvicorn + body: '{"message":"Failed to send SMS. Please check the provided phone number."}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-14T14:56:32.013566624+05:30 + objects: [] + assertions: + noise: + header.Date: [] + created: 1699953992 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/send-sms/ \ + --header 'User-Agent: PostmanRuntime/7.34.0' \ + --header 'Accept: */*' \ + --header 'Postman-Token: c871b715-7aae-46b6-8e0d-1341aa426624' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'Content-Type: application/json' \ + --data '{ + "Body": "Test, testtt, testttttttssss :)", + "To": "+91700004379" + }' diff --git a/fastapi-twilio/keploy/test-set-0/tests/test-2.yaml b/fastapi-twilio/keploy/test-set-0/tests/test-2.yaml new file mode 100755 index 0000000..bb9db1e --- /dev/null +++ b/fastapi-twilio/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,58 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/send-sms/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "76" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: a3780363-733f-4c88-915b-d4d69384822c + User-Agent: PostmanRuntime/7.34.0 + body: |- + { + "Body": "Test, testtt, testttttttssss :)", + "To": "+917000043797" + } + body_type: "" + timestamp: 2023-11-14T14:56:33.722179585+05:30 + resp: + status_code: 200 + header: + Content-Length: "36" + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:26:33 GMT + Server: uvicorn + body: '{"message":"SMS sent successfully!"}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-14T14:56:37.588988851+05:30 + objects: [] + assertions: + noise: + header.Date: [] + created: 1699953997 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/send-sms/ \ + --header 'Content-Type: application/json' \ + --header 'User-Agent: PostmanRuntime/7.34.0' \ + --header 'Accept: */*' \ + --header 'Postman-Token: a3780363-733f-4c88-915b-d4d69384822c' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --data '{ + "Body": "Test, testtt, testttttttssss :)", + "To": "+917000043797" + }' diff --git a/fastapi-twilio/keploy/test-set-0/tests/test-3.yaml b/fastapi-twilio/keploy/test-set-0/tests/test-3.yaml new file mode 100755 index 0000000..3a01fb6 --- /dev/null +++ b/fastapi-twilio/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,58 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/send-sms/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "74" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: 5e8c1a07-c35d-4816-8b32-c6bcfd28d94d + User-Agent: PostmanRuntime/7.34.0 + body: |- + { + "Body": "Test, testtt, testttttttssss :)", + "To": "+9170000437" + } + body_type: "" + timestamp: 2023-11-14T14:57:19.642139975+05:30 + resp: + status_code: 200 + header: + Content-Length: "73" + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:27:18 GMT + Server: uvicorn + body: '{"message":"Failed to send SMS. Please check the provided phone number."}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-14T14:57:23.973137683+05:30 + objects: [] + assertions: + noise: + header.Date: [] + created: 1699954043 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/send-sms/ \ + --header 'Accept: */*' \ + --header 'Postman-Token: 5e8c1a07-c35d-4816-8b32-c6bcfd28d94d' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'Content-Type: application/json' \ + --header 'User-Agent: PostmanRuntime/7.34.0' \ + --data '{ + "Body": "Test, testtt, testttttttssss :)", + "To": "+9170000437" + }' diff --git a/fastapi-twilio/keploy/testReports/report-1.yaml b/fastapi-twilio/keploy/testReports/report-1.yaml new file mode 100755 index 0000000..acf2233 --- /dev/null +++ b/fastapi-twilio/keploy/testReports/report-1.yaml @@ -0,0 +1,284 @@ +version: api.keploy.io/v1beta1 +name: report-1 +status: PASSED +success: 3 +failure: 0 +total: 3 +tests: + - kind: Http + name: report-1 + status: PASSED + started: 1699954104 + completed: 1699954106 + test_case_path: /home/shashwat/test/python-twilio/keploy/test-set-0 + mock_path: "" + test_case_id: test-1 + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/send-sms/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "75" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: c871b715-7aae-46b6-8e0d-1341aa426624 + User-Agent: PostmanRuntime/7.34.0 + body: |- + { + "Body": "Test, testtt, testttttttssss :)", + "To": "+91700004379" + } + body_type: "" + timestamp: 0001-01-01T00:00:00Z + resp: + status_code: 200 + header: + Content-Length: "73" + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:26:25 GMT + Server: uvicorn + body: '{"message":"Failed to send SMS. Please check the provided phone number."}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Length + value: + - "73" + actual: + key: Content-Length + value: + - "73" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Tue, 14 Nov 2023 09:26:25 GMT + actual: + key: Date + value: + - Tue, 14 Nov 2023 09:28:24 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + body_result: + - normal: true + type: JSON + expected: '{"message":"Failed to send SMS. Please check the provided phone number."}' + actual: '{"message":"Failed to send SMS. Please check the provided phone number."}' + dep_result: [] + - kind: Http + name: report-1 + status: PASSED + started: 1699954106 + completed: 1699954107 + test_case_path: /home/shashwat/test/python-twilio/keploy/test-set-0 + mock_path: "" + test_case_id: test-2 + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/send-sms/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "76" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: a3780363-733f-4c88-915b-d4d69384822c + User-Agent: PostmanRuntime/7.34.0 + body: |- + { + "Body": "Test, testtt, testttttttssss :)", + "To": "+917000043797" + } + body_type: "" + timestamp: 0001-01-01T00:00:00Z + resp: + status_code: 200 + header: + Content-Length: "36" + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:26:33 GMT + Server: uvicorn + body: '{"message":"SMS sent successfully!"}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Tue, 14 Nov 2023 09:26:33 GMT + actual: + key: Date + value: + - Tue, 14 Nov 2023 09:28:26 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + - normal: true + expected: + key: Content-Length + value: + - "36" + actual: + key: Content-Length + value: + - "36" + body_result: + - normal: true + type: JSON + expected: '{"message":"SMS sent successfully!"}' + actual: '{"message":"SMS sent successfully!"}' + dep_result: [] + - kind: Http + name: report-1 + status: PASSED + started: 1699954107 + completed: 1699954108 + test_case_path: /home/shashwat/test/python-twilio/keploy/test-set-0 + mock_path: "" + test_case_id: test-3 + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/send-sms/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: keep-alive + Content-Length: "74" + Content-Type: application/json + Host: 127.0.0.1:8000 + Postman-Token: 5e8c1a07-c35d-4816-8b32-c6bcfd28d94d + User-Agent: PostmanRuntime/7.34.0 + body: |- + { + "Body": "Test, testtt, testttttttssss :)", + "To": "+9170000437" + } + body_type: "" + timestamp: 0001-01-01T00:00:00Z + resp: + status_code: 200 + header: + Content-Length: "73" + Content-Type: application/json + Date: Tue, 14 Nov 2023 09:27:18 GMT + Server: uvicorn + body: '{"message":"Failed to send SMS. Please check the provided phone number."}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Tue, 14 Nov 2023 09:27:18 GMT + actual: + key: Date + value: + - Tue, 14 Nov 2023 09:28:27 GMT + - normal: true + expected: + key: Server + value: + - uvicorn + actual: + key: Server + value: + - uvicorn + - normal: true + expected: + key: Content-Length + value: + - "73" + actual: + key: Content-Length + value: + - "73" + body_result: + - normal: true + type: JSON + expected: '{"message":"Failed to send SMS. Please check the provided phone number."}' + actual: '{"message":"Failed to send SMS. Please check the provided phone number."}' + dep_result: [] +test_set: test-set-0 diff --git a/fastapi-twilio/main.py b/fastapi-twilio/main.py new file mode 100644 index 0000000..82800cd --- /dev/null +++ b/fastapi-twilio/main.py @@ -0,0 +1,39 @@ +from fastapi import FastAPI +import requests +from dotenv import load_dotenv +from pydantic import BaseModel +import os + + +load_dotenv() + + +class Message(BaseModel): + Body: str + To: str + +app = FastAPI() + + +@app.post('/send-sms/') +def send_sms(data: Message): + twilio_account_sid = os.getenv('TWILIO_ACCOUNT_SID') + twilio_auth_token = os.getenv('TWILIO_AUTH_TOKEN') + twilio_phone_number = os.getenv('TWILIO_NUMBER') + + url = f'https://api.twilio.com/2010-04-01/Accounts/{twilio_account_sid}/Messages.json' + + payload = { + 'Body': data.Body, + 'From': twilio_phone_number, + 'To': data.To + } + + try: + response = requests.post(url=url, data=payload, auth=(twilio_account_sid, twilio_auth_token)) + if response.status_code == 201: + return {"message": "SMS sent successfully!"} + else: + return {"message": "Failed to send SMS. Please check the provided phone number."} + except Exception as e: + return {"message": str(e)} diff --git a/fastapi-twilio/requirements.txt b/fastapi-twilio/requirements.txt new file mode 100644 index 0000000..d86cb8b --- /dev/null +++ b/fastapi-twilio/requirements.txt @@ -0,0 +1,28 @@ +aiohttp==3.8.6 +aiohttp-retry==2.8.3 +aiosignal==1.3.1 +annotated-types==0.6.0 +anyio==3.7.1 +async-timeout==4.0.3 +attrs==23.1.0 +certifi==2023.7.22 +charset-normalizer==3.3.2 +click==8.1.7 +exceptiongroup==1.1.3 +fastapi==0.104.1 +frozenlist==1.4.0 +h11==0.14.0 +idna==3.4 +multidict==6.0.4 +pydantic==2.4.2 +pydantic_core==2.10.1 +PyJWT==2.8.0 +python-dotenv==1.0.0 +requests==2.31.0 +sniffio==1.3.0 +starlette==0.27.0 +twilio==8.10.1 +typing_extensions==4.8.0 +urllib3==2.0.7 +uvicorn==0.24.0.post1 +yarl==1.9.2 From 0bd58eb93b84961c35da4d697c8827f6353eab8a Mon Sep 17 00:00:00 2001 From: Shashwat79802 Date: Tue, 12 Dec 2023 16:07:17 +0530 Subject: [PATCH 05/31] fix: updated requirements file, docker-compose config Signed-off-by: Shashwat79802 --- flask-mongo/app.py | 1 + flask-mongo/docker-compose.yml | 1 + flask-mongo/requirements.txt | 5 +++-- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/flask-mongo/app.py b/flask-mongo/app.py index 3533f16..6e31416 100644 --- a/flask-mongo/app.py +++ b/flask-mongo/app.py @@ -1,6 +1,7 @@ from flask import Flask, request, jsonify from pymongo import MongoClient from flask_cors import CORS +import collections.abc app = Flask(__name__) cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) diff --git a/flask-mongo/docker-compose.yml b/flask-mongo/docker-compose.yml index 1991b57..7ef7346 100644 --- a/flask-mongo/docker-compose.yml +++ b/flask-mongo/docker-compose.yml @@ -11,6 +11,7 @@ services: - backend flask-app: + image: flask-app:1.0 container_name: flask-app build: context: . diff --git a/flask-mongo/requirements.txt b/flask-mongo/requirements.txt index d7045e9..7a03746 100644 --- a/flask-mongo/requirements.txt +++ b/flask-mongo/requirements.txt @@ -1,3 +1,4 @@ -Flask==2.0.1 +Flask pymongo==4.4.1 -Flask-Cors==3.0.1 +Flask-Cors==3.0.10 +Werkzeug==2.2.2 \ No newline at end of file From b467f109daf8810aad5704bbbecc1ba5470dd716 Mon Sep 17 00:00:00 2001 From: Prajwal Deshpande Date: Tue, 30 Jan 2024 18:42:09 +0530 Subject: [PATCH 06/31] feat: added new requirements & changed port to 5432 (#11) Signed-off-by: Prajwal Co-authored-by: Prajwal --- .../django_postgres/django_postgres/settings.py | 2 +- django-postgres/django_postgres/requirements.txt | 12 ++++++++---- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/django-postgres/django_postgres/django_postgres/settings.py b/django-postgres/django_postgres/django_postgres/settings.py index abe5353..2791ed4 100644 --- a/django-postgres/django_postgres/django_postgres/settings.py +++ b/django-postgres/django_postgres/django_postgres/settings.py @@ -82,7 +82,7 @@ 'USER': 'postgres', 'PASSWORD': 'postgres', 'HOST': '0.0.0.0', - 'PORT': '6000', + 'PORT': '5432', } } diff --git a/django-postgres/django_postgres/requirements.txt b/django-postgres/django_postgres/requirements.txt index eb2fff9..5d51161 100644 --- a/django-postgres/django_postgres/requirements.txt +++ b/django-postgres/django_postgres/requirements.txt @@ -1,4 +1,8 @@ -django==4.2.3 -django_rest_framework==0.1.0 -psycopg2-binary==2.9.6 -psycopg2>=2.7,<3.0 \ No newline at end of file +asgiref==3.7.2 +Django==4.2.9 +djangorestframework==3.14.0 +psycopg==3.1.17 +psycopg2-binary==2.9.9 +pytz==2023.3.post1 +sqlparse==0.4.4 +typing_extensions==4.9.0 From fe09284112e8d9a697a83198bb093e750bda96e0 Mon Sep 17 00:00:00 2001 From: Animesh pathak Date: Fri, 9 Feb 2024 10:29:58 +0000 Subject: [PATCH 07/31] fix: app running command Signed-off-by: Animesh pathak --- fastapi-postgres/Dockerfile | 12 +- fastapi-postgres/keploy/test-set-1/mocks.yaml | 1219 +++++++++++++++++ .../keploy/test-set-1/tests/test-1.yaml | 55 + .../keploy/test-set-1/tests/test-2.yaml | 55 + fastapi-postgres/requirements.txt | 3 +- 5 files changed, 1336 insertions(+), 8 deletions(-) create mode 100755 fastapi-postgres/keploy/test-set-1/mocks.yaml create mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-1.yaml create mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-2.yaml diff --git a/fastapi-postgres/Dockerfile b/fastapi-postgres/Dockerfile index 8dfa645..dc51d4b 100644 --- a/fastapi-postgres/Dockerfile +++ b/fastapi-postgres/Dockerfile @@ -14,11 +14,11 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . . # Set environment variables for PostgreSQL -ENV POSTGRES_USER=postgres \ - POSTGRES_PASSWORD=postgres \ - POSTGRES_DB=studentdb \ - POSTGRES_HOST=0.0.0.0 \ - POSTGRES_PORT=5432 +# ENV POSTGRES_USER=postgres \ +# POSTGRES_PASSWORD=postgres \ +# POSTGRES_DB=studentdb \ +# POSTGRES_HOST=0.0.0.0 \ +# POSTGRES_PORT=5432 # Install PostgreSQL client RUN apt-get update && apt-get install -y postgresql-client @@ -27,4 +27,4 @@ RUN apt-get update && apt-get install -y postgresql-client EXPOSE 8000 # Start the FastAPI application -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] +CMD ["uvicorn", "application.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/fastapi-postgres/keploy/test-set-1/mocks.yaml b/fastapi-postgres/keploy/test-set-1/mocks.yaml new file mode 100755 index 0000000..86b47c1 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-1/mocks.yaml @@ -0,0 +1,1219 @@ +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-0 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.216898875Z + restimestampmock: 2024-02-09T10:20:50.218562705Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-1 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl: + auth_mechanisms: + - SCRAM-SHA-256 + msg_type: 82 + auth_type: 10 + reqtimestampmock: 2024-02-09T10:20:50.232737784Z + restimestampmock: 2024-02-09T10:20:50.233296602Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-2 +spec: + metadata: + type: config + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + password_message: + password: SCRAM-SHA-256 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_continue: {data: [114, 61, 68, 54, 118, 109, 56, 118, 117, 82, 116, 89, 111, 116, 75, 81, 75, 86, 74, 100, 55, 47, 85, 115, 107, 90, 70, 78, 88, 79, 112, 80, 88, 84, 67, 105, 103, 86, 51, 101, 73, 90, 48, 105, 119, 117, 65, 106, 111, 83, 44, 115, 61, 117, 110, 74, 50, 122, 68, 57, 75, 121, 76, 47, 109, 83, 114, 117, 111, 102, 121, 55, 112, 84, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} + msg_type: 82 + auth_type: 11 + reqtimestampmock: 2024-02-09T10:20:50.234459113Z + restimestampmock: 2024-02-09T10:20:50.234488904Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-3 +spec: + metadata: + type: config + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_final: {data: [118, 61, 118, 48, 53, 82, 117, 66, 89, 50, 52, 51, 72, 85, 67, 97, 116, 102, 83, 55, 67, 69, 70, 43, 72, 84, 106, 89, 90, 79, 118, 115, 115, 78, 48, 56, 116, 120, 99, 48, 103, 106, 105, 119, 85, 61]} + backend_key_data: + process_id: 34 + secret_key: 4065475156 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Etc/UTC + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "on" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: postgres + - name: client_encoding + value: UTF8 + - name: server_version + value: 16.1 (Debian 16.1-1.pgdg120+1) + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.240419203Z + restimestampmock: 2024-02-09T10:20:50.24047866Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-4 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.241574547Z + restimestampmock: 2024-02-09T10:20:50.241651254Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-5 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAHdTRUxFQ1QgdC5vaWQsIHR5cGFycmF5CkZST00gcGdfdHlwZSB0IEpPSU4gcGdfbmFtZXNwYWNlIG5zCiAgICBPTiB0eXBuYW1lc3BhY2UgPSBucy5vaWQKV0hFUkUgdHlwbmFtZSA9ICdoc3RvcmUnOwoA + query: + string: 'SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid WHERE typname = ''hstore''; ' + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [111, 105, 100], table_oid: 1247, table_attribute_number: 1, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}, {name: [116, 121, 112, 97, 114, 114, 97, 121], table_oid: 1247, table_attribute_number: 15, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.243360791Z + restimestampmock: 2024-02-09T10:20:50.243385416Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-6 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.244072772Z + restimestampmock: 2024-02-09T10:20:50.244098563Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-7 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.244693006Z + restimestampmock: 2024-02-09T10:20:50.244715338Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-8 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select pg_catalog.version() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAACAAAXZlcnNpb24AAAAAAAAAAAAAGf///////wAARAAAAIMAAQAAAHlQb3N0Z3JlU1FMIDE2LjEgKERlYmlhbiAxNi4xLTEucGdkZzEyMCsxKSBvbiBhYXJjaDY0LXVua25vd24tbGludXgtZ251LCBjb21waWxlZCBieSBnY2MgKERlYmlhbiAxMi4yLjAtMTQpIDEyLjIuMCwgNjQtYml0QwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [118, 101, 114, 115, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.24516216Z + restimestampmock: 2024-02-09T10:20:50.245191367Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-9 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select current_schema() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAACcAAWN1cnJlbnRfc2NoZW1hAAAAAAAAAAAAABMAQP////8AAEQAAAAQAAEAAAAGcHVibGljQwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: [public]}, {row_values: [public]}, {row_values: [public]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [99, 117, 114, 114, 101, 110, 116, 95, 115, 99, 104, 101, 109, 97], table_oid: 0, table_attribute_number: 0, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.246241214Z + restimestampmock: 2024-02-09T10:20:50.246281713Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-10 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show transaction isolation level + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAAC4AAXRyYW5zYWN0aW9uX2lzb2xhdGlvbgAAAAAAAAAAAAAZ////////AABEAAAAGAABAAAADnJlYWQgY29tbWl0dGVkQwAAAAlTSE9XAFoAAAAFVA== + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 72 + - 79 + - 87 + data_row: [{row_values: [read committed]}, {row_values: [read committed]}, {row_values: [read committed]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 95, 105, 115, 111, 108, 97, 116, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.247356559Z + restimestampmock: 2024-02-09T10:20:50.247387933Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-11 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show standard_conforming_strings + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAADQAAXN0YW5kYXJkX2NvbmZvcm1pbmdfc3RyaW5ncwAAAAAAAAAAAAAZ////////AABEAAAADAABAAAAAm9uQwAAAAlTSE9XAFoAAAAFVA== + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 72 + - 79 + - 87 + data_row: [{row_values: ["on"]}, {row_values: ["on"]}, {row_values: ["on"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 97, 110, 100, 97, 114, 100, 95, 99, 111, 110, 102, 111, 114, 109, 105, 110, 103, 95, 115, 116, 114, 105, 110, 103, 115], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.248114456Z + restimestampmock: 2024-02-09T10:20:50.24815283Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-12 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.248975766Z + restimestampmock: 2024-02-09T10:20:50.24899789Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-13 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.252045225Z + restimestampmock: 2024-02-09T10:20:50.252072266Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-14 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAYdTRUxFQ1QgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lIApGUk9NIHBnX2NhdGFsb2cucGdfY2xhc3MgSk9JTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZSBPTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5vaWQgPSBwZ19jYXRhbG9nLnBnX2NsYXNzLnJlbG5hbWVzcGFjZSAKV0hFUkUgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lID0gJ3N0dWRlbnRzJyBBTkQgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxraW5kID0gQU5ZIChBUlJBWVsncicsICdwJywgJ2YnLCAndicsICdtJ10pIEFORCBwZ19jYXRhbG9nLnBnX3RhYmxlX2lzX3Zpc2libGUocGdfY2F0YWxvZy5wZ19jbGFzcy5vaWQpIEFORCBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5uc3BuYW1lICE9ICdwZ19jYXRhbG9nJwA= + query: + string: SELECT pg_catalog.pg_class.relname FROM pg_catalog.pg_class JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.oid = pg_catalog.pg_class.relnamespace WHERE pg_catalog.pg_class.relname = 'students' AND pg_catalog.pg_class.relkind = ANY (ARRAY['r', 'p', 'f', 'v', 'm']) AND pg_catalog.pg_table_is_visible(pg_catalog.pg_class.oid) AND pg_catalog.pg_namespace.nspname != 'pg_catalog' + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAACAAAXJlbG5hbWUAAAAE6wACAAAAEwBA/////wAARAAAABIAAQAAAAhzdHVkZW50c0MAAAANU0VMRUNUIDEAWgAAAAVU + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: [students]}, {row_values: [students]}, {row_values: [students]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [114, 101, 108, 110, 97, 109, 101], table_oid: 1259, table_attribute_number: 2, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.253162445Z + restimestampmock: 2024-02-09T10:20:50.253222319Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-15 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.254107087Z + restimestampmock: 2024-02-09T10:20:50.25412767Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-16 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.542685552Z + restimestampmock: 2024-02-09T10:21:01.542714843Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-17 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAATBTRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnZXZhd2hpdGVAZXhhbXBsZS5jb20nIAogTElNSVQgMQA= + query: + string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'evawhite@example.com' LIMIT 1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.543969268Z + restimestampmock: 2024-02-09T10:21:01.544053057Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-18 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('Eva White', 'evawhite@example.com', 'sfwbxijuf222', 'Mathematics') RETURNING students."ID" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMUMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 73 + - 78 + - 83 + - 69 + - 82 + - 84 + - 32 + - 48 + - 32 + - 49 + data_row: [{row_values: ["1"]}, {row_values: ["1"]}, {row_values: ["1"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.546426702Z + restimestampmock: 2024-02-09T10:21:01.546463701Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-19 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.551006372Z + restimestampmock: 2024-02-09T10:21:01.55108062Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-20 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.552699118Z + restimestampmock: 2024-02-09T10:21:01.552721743Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-21 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDEA + query: + string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABPAAUAAAABMQAAAAlFdmEgV2hpdGUAAAAUZXZhd2hpdGVAZXhhbXBsZS5jb20AAAAMc2Z3YnhpanVmMjIyAAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.553203147Z + restimestampmock: 2024-02-09T10:21:01.553236062Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-22 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.556089153Z + restimestampmock: 2024-02-09T10:21:01.556110861Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-23 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.223148624Z + restimestampmock: 2024-02-09T10:21:11.223211164Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-24 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAS9TRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnam9obmRvZUBleGFtcGxlLmNvbScgCiBMSU1JVCAxAA== + query: + string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'johndoe@example.com' LIMIT 1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.224563961Z + restimestampmock: 2024-02-09T10:21:11.224606043Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-25 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('John Doe', 'johndoe@example.com', 'skpioepf234', 'Mathematics') RETURNING students."ID" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMkMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 73 + - 78 + - 83 + - 69 + - 82 + - 84 + - 32 + - 48 + - 32 + - 49 + data_row: [{row_values: ["2"]}, {row_values: ["2"]}, {row_values: ["2"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.226669655Z + restimestampmock: 2024-02-09T10:21:11.226748861Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-26 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.232155218Z + restimestampmock: 2024-02-09T10:21:11.232190134Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-27 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.233212565Z + restimestampmock: 2024-02-09T10:21:11.233238147Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-28 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDIA + query: + string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 2 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABMAAUAAAABMgAAAAhKb2huIERvZQAAABNqb2huZG9lQGV4YW1wbGUuY29tAAAAC3NrcGlvZXBmMjM0AAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.233889547Z + restimestampmock: 2024-02-09T10:21:11.233922754Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-29 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.236845177Z + restimestampmock: 2024-02-09T10:21:11.236868259Z diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml new file mode 100755 index 0000000..e5100d2 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml @@ -0,0 +1,55 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Content-Length: "105" + Content-Type: application/json + Host: 127.0.0.1:8000 + User-Agent: curl/8.2.1 + body: |- + { + "name": "Eva White", + "email": "evawhite@example.com", + "password": "evawhite111" + } + body_type: "" + timestamp: 2024-02-09T10:21:01.532943145Z + host: "" + resp: + status_code: 200 + header: + Content-Length: "107" + Content-Type: application/json + Date: Fri, 09 Feb 2024 10:21:00 GMT + Server: uvicorn + body: '{"name":"Eva White","email":"evawhite@example.com","password":"sfwbxijuf222","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2024-02-09T10:21:03.574647019Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1707474063 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/students/ \ + --header 'Host: 127.0.0.1:8000' \ + --header 'User-Agent: curl/8.2.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{ + "name": "Eva White", + "email": "evawhite@example.com", + "password": "evawhite111" + }' diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml new file mode 100755 index 0000000..ecddaf6 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml @@ -0,0 +1,55 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Content-Length: "106" + Content-Type: application/json + Host: 127.0.0.1:8000 + User-Agent: curl/8.2.1 + body: |4- + { + "name": "John Doe", + "email": "johndoe@example.com", + "password": "johndoe123" + } + body_type: "" + timestamp: 2024-02-09T10:21:11.21894436Z + host: "" + resp: + status_code: 200 + header: + Content-Length: "104" + Content-Type: application/json + Date: Fri, 09 Feb 2024 10:21:10 GMT + Server: uvicorn + body: '{"name":"John Doe","email":"johndoe@example.com","password":"skpioepf234","stream":"Mathematics","id":2}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2024-02-09T10:21:13.238027535Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1707474073 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/students/ \ + --header 'User-Agent: curl/8.2.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Host: 127.0.0.1:8000' \ + --data ' { + "name": "John Doe", + "email": "johndoe@example.com", + "password": "johndoe123" + }' diff --git a/fastapi-postgres/requirements.txt b/fastapi-postgres/requirements.txt index 946ca50..5201c90 100644 --- a/fastapi-postgres/requirements.txt +++ b/fastapi-postgres/requirements.txt @@ -22,7 +22,6 @@ pydantic==2.4.2 pydantic-extra-types==2.1.0 pydantic-settings==2.0.3 pydantic_core==2.10.1 -pyscopg2==66.0.2 python-dotenv==1.0.0 python-multipart==0.0.6 PyYAML==6.0.1 @@ -34,4 +33,4 @@ ujson==5.8.0 uvicorn==0.23.2 uvloop==0.17.0 watchfiles==0.20.0 -websockets==11.0.3 \ No newline at end of file +websockets==11.0.3 From 66c2ffd8b37c9d364658157d3edc99d942a25b56 Mon Sep 17 00:00:00 2001 From: Animesh Pathak <53110238+Sonichigo@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:02:07 +0530 Subject: [PATCH 08/31] feat: added missing steps (#10) * feat: added missing steps Signed-off-by: Animesh * fix: removed uncessary lines Signed-off-by: Animesh --------- Signed-off-by: Animesh --- flask-mongo/README.md | 606 ++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 588 insertions(+), 18 deletions(-) diff --git a/flask-mongo/README.md b/flask-mongo/README.md index 8080c5f..54bc693 100644 --- a/flask-mongo/README.md +++ b/flask-mongo/README.md @@ -1,30 +1,600 @@ This application is a simple student management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. +## Table of Contents -Usage: +# Introduction -1. Get List of Students: Retrieve a list of all students. -``` -curl http://localhost:6000/students -``` +🪄 Dive into the world of Student CRUD Apps and see how seamlessly Keploy integrated with [Flask](https://flask.palletsprojects.com/en/3.0.x/) and [MongoDB](https://www.mongodb.com/). Buckle up, it's gonna be a fun ride! 🎢 -2. Get Student by ID: Retrieve details of a specific student using their student ID. -``` -curl http://localhost:6000/students/12345 -``` +## Pre-Requisite 🛠️ -3. Create a New Student: Add a new student record to the database. +- Install WSL (`wsl --install`) for Windows Windows. -``` -curl -X POST -H "Content-Type: application/json" -d '{"student_id": "12345", "name": "John Doe", "age": 20}' http://localhost:6000/students -``` +## Optional 🛠️ + +- Install Colima( `brew install colima && colima start` ) for MacOS MacOs. + +## Get Started! 🎬 + +## Setup the MongoDB Database 📦 -4. Update Student Information: Update details of an existing student using their student ID. +Create a docker network, run - + +```bash +docker network create backend ``` -curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + +Start the MongoDB instance- + +```bash +docker run -p 27017:27017 -d --network backend --name mongo mongo ``` -5. Delete Student: Delete a student record by their student ID. +## Clone a simple Student Management API 🧪 + +```bash +git clone https://github.com/keploy/samples-python.git && cd samples-python/flask-mongo ``` -curl -X DELETE http://localhost:6000/students/12345 -``` \ No newline at end of file + +## Installation 📥 + +Depending on your OS, choose your adventure: + +-
+ Linux Linux or Windows Windows + + Alright, let's equip ourselves with the **latest Keploy binary**: + + ```bash + curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp + + sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy + ``` + + If everything goes right, your screen should look a bit like this: + + Moving on... +
+ Run App with Docker Container Docker + + #### Add alias for Keploy: + + ```bash + alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' + ``` + + ### Lights, Camera, Record! 🎥 + + Build the app image: + + ```bash + docker build -t flask-app:1.0 . + ``` + + Capture the test-cases- + + ```shell + keploy record -c "docker run -p 6000:6000 --name flask-app --network backend flask-app:1.0" + ``` + + 🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! + + Let's make URLs short and sweet: + + ### Generate testcases + + To generate testcases we just need to **make some API calls.** + + **1. Make a POST request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **2. Make a GET request** + + ```bash + curl http://localhost:6000/students + ``` + + **3. Make a PUT request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **4. Make a GET request** + + ```bash + curl http://localhost:6000/students/12345 + ``` + + **5. Make a DELETE request** + + ```bash + curl -X DELETE http://localhost:6000/students/12345 + ``` + + Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. + + ```yaml + version: api.keploy.io/v1beta2 + kind: Http + name: test-1 + spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:6000/students + header: + Accept: "*/*" + Content-Length: "56" + Content-Type: application/json + Host: localhost:6000 + User-Agent: curl/7.81.0 + body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' + body_type: "" + timestamp: 2023-11-13T13:02:32.241333562Z + resp: + status_code: 200 + header: + Content-Length: "48" + Content-Type: application/json + Date: Mon, 13 Nov 2023 13:02:32 GMT + Server: Werkzeug/2.2.2 Python/3.9.18 + body: | + { + "message": "Student created successfully" + } + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-13T13:02:34.752123715Z + objects: [] + assertions: + noise: + - header.Date + created: 1699880554 + curl: |- + curl --request POST \ + --url http://localhost:6000/students \ + --header 'Host: localhost:6000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' + ``` + + This is how `mocks.yml` generated would look like:- + + ```yaml + version: api.keploy.io/v1beta2 + kind: Mongo + name: mocks + spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' + requests: + - header: + length: 187 + requestId: 2127584089 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' + checksum: 0 + read_delay: 3469848802 + responses: + - header: + length: 166 + requestId: 154 + responseTo: 2127584089 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 869555 + created: 1699880576 + reqTimestampMock: 2023-11-13T13:02:56.385067848Z + resTimestampMock: 2023-11-13T13:02:56.386374941Z + ``` + + Want to see if everything works as expected? + + #### Run Tests + + Time to put things to the test 🧪 + + ```shell + keploy test -c "sudo docker run -p 6000:6000 --rm --network backend --name flask-app flask-app:1.0" --delay 10 + ``` + + > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. + + Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ + + ## Wrapping it up 🎉 + + Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 + + Happy coding! ✨👩‍💻👨‍💻✨ + +
+
+ +
+ Run App on 🐧 Linux + + We'll be running our sample application right on Linux, but just to make things a tad more thrilling, we'll have the database (PostgreSQL) chill on Docker. Ready? Let's get the party started!🎉 + + ### 📼 Roll the Tape - Recording Time! + + Install the dependencies: + + ```bash + pip install -r requirements.txt + ``` + + Now, let's Capture the test-cases- + + In `app.py`, replace the MongoDB connection URL with - `mongodb://0.0.0.0:27017/` + + Ready, set, record! Here's how: + + ```bash + keploy record -c "python3 app.py" + ``` + + Keep an eye out for the `-c `flag! It's the command charm to run the app. + + Alright, magician! With the app alive and kicking, let's weave some test cases. The spell? Making some API calls! Postman, Hoppscotch, or the classic curl - pick your wand. + + ### Generate testcases + + To generate testcases we just need to **make some API calls.** + + **1. Make a POST request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **2. Make a GET request** + + ```bash + curl http://localhost:6000/students + ``` + + **3. Make a PUT request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **4. Make a GET request** + + ```bash + curl http://localhost:6000/students/12345 + ``` + + **5. Make a DELETE request** + + ```bash + curl -X DELETE http://localhost:6000/students/12345 + ``` + + Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. + + ```yaml + version: api.keploy.io/v1beta2 + kind: Http + name: test-1 + spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:6000/students + header: + Accept: "*/*" + Content-Length: "56" + Content-Type: application/json + Host: localhost:6000 + User-Agent: curl/7.81.0 + body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' + body_type: "" + timestamp: 2023-11-13T13:02:32.241333562Z + resp: + status_code: 200 + header: + Content-Length: "48" + Content-Type: application/json + Date: Mon, 13 Nov 2023 13:02:32 GMT + Server: Werkzeug/2.2.2 Python/3.9.18 + body: | + { + "message": "Student created successfully" + } + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-13T13:02:34.752123715Z + objects: [] + assertions: + noise: + - header.Date + created: 1699880554 + curl: |- + curl --request POST \ + --url http://localhost:6000/students \ + --header 'Host: localhost:6000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' + ``` + + This is how `mocks.yml` generated would look like:- + + ```yaml + version: api.keploy.io/v1beta2 + kind: Mongo + name: mocks + spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' + requests: + - header: + length: 187 + requestId: 2127584089 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' + checksum: 0 + read_delay: 3469848802 + responses: + - header: + length: 166 + requestId: 154 + responseTo: 2127584089 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 869555 + created: 1699880576 + reqTimestampMock: 2023-11-13T13:02:56.385067848Z + resTimestampMock: 2023-11-13T13:02:56.386374941Z + ``` + + Want to see if everything works as expected? + + #### Run Tests + + Time to put things to the test 🧪 + + ```shell + keploy test -c "python3 app.py" --delay 10 + ``` + + > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. + + Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ + + ## Wrapping it up 🎉 + + Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible. 😊🚀 + + Happy coding! ✨👩‍💻👨‍💻✨ +
+ +
+ +
+ +-
+ MacOS MacOs + + Dive straight in, but first in case you're using **Keploy** with **Colima**, give it a gentle nudge with (`colima start`). Let's make sure it's awake and ready for action! + + ### Add alias for Keploy 🐰: + + For the sake of convenience (and a bit of Mac magic 🪄), let's set up a shortcut for Keploy: + + ### Use Keploy with Docker-Desktop + + Note: To run Keploy on MacOS through [Docker](https://docs.docker.com/desktop/release-notes/#4252) the version must be `4.25.2` or above. + + #### Creating Docker Volume + + ```bash + docker volume create --driver local --opt type=debugfs --opt device=debugfs debugfs + ``` + + ```bash + alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v debugfs:/sys/kernel/debug:rw -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' + ``` + + ### Use Keploy with Colima + + ```bash + alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' + ``` + + ### Lights, Camera, Record! 🎥 + + Build the app image: + + ```bash + docker build -t flask-app:1.0 . + ``` + + Capture the test-cases- + + ```shell + keploy record -c "docker run -p 6000:6000 --name DjangoApp --network backend --name flask-app flask-app:1.0" + ``` + + 🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! + + Let's make URLs short and sweet: + + ### Generate testcases + + To generate testcases we just need to **make some API calls.** + + **1. Make a POST request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **2. Make a GET request** + + ```bash + curl http://localhost:6000/students + ``` + + **3. Make a PUT request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **4. Make a GET request** + + ```bash + curl http://localhost:6000/students/12345 + ``` + + **5. Make a DELETE request** + + ```bash + curl -X DELETE http://localhost:6000/students/12345 + ``` + + Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. + + ```yaml + version: api.keploy.io/v1beta2 + kind: Http + name: test-1 + spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:6000/students + header: + Accept: "*/*" + Content-Length: "56" + Content-Type: application/json + Host: localhost:6000 + User-Agent: curl/7.81.0 + body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' + body_type: "" + timestamp: 2023-11-13T13:02:32.241333562Z + resp: + status_code: 200 + header: + Content-Length: "48" + Content-Type: application/json + Date: Mon, 13 Nov 2023 13:02:32 GMT + Server: Werkzeug/2.2.2 Python/3.9.18 + body: | + { + "message": "Student created successfully" + } + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-13T13:02:34.752123715Z + objects: [] + assertions: + noise: + - header.Date + created: 1699880554 + curl: |- + curl --request POST \ + --url http://localhost:6000/students \ + --header 'Host: localhost:6000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' + ``` + + This is how `mocks.yml` generated would look like:- + + ```yaml + version: api.keploy.io/v1beta2 + kind: Mongo + name: mocks + spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' + requests: + - header: + length: 187 + requestId: 2127584089 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' + checksum: 0 + read_delay: 3469848802 + responses: + - header: + length: 166 + requestId: 154 + responseTo: 2127584089 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 869555 + created: 1699880576 + reqTimestampMock: 2023-11-13T13:02:56.385067848Z + resTimestampMock: 2023-11-13T13:02:56.386374941Z + ``` + + Want to see if everything works as expected? + + #### Run Tests + + Time to put things to the test 🧪 + + ```shell + keploy test -c "sudo docker run -p 6000:6000 --rm --network backend --name flask-app flask-app:1.0" --delay 10 + ``` + + > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. + + Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ + + ## Wrapping it up 🎉 + + Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 + + Happy coding! ✨👩‍💻👨‍💻✨ +
From 6426975ee98e6c62e556f6c6919a4a710c65e16d Mon Sep 17 00:00:00 2001 From: Animesh Pathak <53110238+Sonichigo@users.noreply.github.com> Date: Fri, 9 Feb 2024 17:02:22 +0530 Subject: [PATCH 09/31] fix: app running command (#12) Signed-off-by: Animesh pathak --- fastapi-postgres/Dockerfile | 12 +- fastapi-postgres/keploy/test-set-1/mocks.yaml | 1219 +++++++++++++++++ .../keploy/test-set-1/tests/test-1.yaml | 55 + .../keploy/test-set-1/tests/test-2.yaml | 55 + fastapi-postgres/requirements.txt | 3 +- 5 files changed, 1336 insertions(+), 8 deletions(-) create mode 100755 fastapi-postgres/keploy/test-set-1/mocks.yaml create mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-1.yaml create mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-2.yaml diff --git a/fastapi-postgres/Dockerfile b/fastapi-postgres/Dockerfile index 8dfa645..dc51d4b 100644 --- a/fastapi-postgres/Dockerfile +++ b/fastapi-postgres/Dockerfile @@ -14,11 +14,11 @@ RUN pip install --no-cache-dir -r requirements.txt COPY . . # Set environment variables for PostgreSQL -ENV POSTGRES_USER=postgres \ - POSTGRES_PASSWORD=postgres \ - POSTGRES_DB=studentdb \ - POSTGRES_HOST=0.0.0.0 \ - POSTGRES_PORT=5432 +# ENV POSTGRES_USER=postgres \ +# POSTGRES_PASSWORD=postgres \ +# POSTGRES_DB=studentdb \ +# POSTGRES_HOST=0.0.0.0 \ +# POSTGRES_PORT=5432 # Install PostgreSQL client RUN apt-get update && apt-get install -y postgresql-client @@ -27,4 +27,4 @@ RUN apt-get update && apt-get install -y postgresql-client EXPOSE 8000 # Start the FastAPI application -CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] +CMD ["uvicorn", "application.main:app", "--host", "0.0.0.0", "--port", "8000"] diff --git a/fastapi-postgres/keploy/test-set-1/mocks.yaml b/fastapi-postgres/keploy/test-set-1/mocks.yaml new file mode 100755 index 0000000..86b47c1 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-1/mocks.yaml @@ -0,0 +1,1219 @@ +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-0 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.216898875Z + restimestampmock: 2024-02-09T10:20:50.218562705Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-1 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl: + auth_mechanisms: + - SCRAM-SHA-256 + msg_type: 82 + auth_type: 10 + reqtimestampmock: 2024-02-09T10:20:50.232737784Z + restimestampmock: 2024-02-09T10:20:50.233296602Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-2 +spec: + metadata: + type: config + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + password_message: + password: SCRAM-SHA-256 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_continue: {data: [114, 61, 68, 54, 118, 109, 56, 118, 117, 82, 116, 89, 111, 116, 75, 81, 75, 86, 74, 100, 55, 47, 85, 115, 107, 90, 70, 78, 88, 79, 112, 80, 88, 84, 67, 105, 103, 86, 51, 101, 73, 90, 48, 105, 119, 117, 65, 106, 111, 83, 44, 115, 61, 117, 110, 74, 50, 122, 68, 57, 75, 121, 76, 47, 109, 83, 114, 117, 111, 102, 121, 55, 112, 84, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} + msg_type: 82 + auth_type: 11 + reqtimestampmock: 2024-02-09T10:20:50.234459113Z + restimestampmock: 2024-02-09T10:20:50.234488904Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-3 +spec: + metadata: + type: config + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + authentication_sasl_final: {data: [118, 61, 118, 48, 53, 82, 117, 66, 89, 50, 52, 51, 72, 85, 67, 97, 116, 102, 83, 55, 67, 69, 70, 43, 72, 84, 106, 89, 90, 79, 118, 115, 115, 78, 48, 56, 116, 120, 99, 48, 103, 106, 105, 119, 85, 61]} + backend_key_data: + process_id: 34 + secret_key: 4065475156 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Etc/UTC + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "on" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: postgres + - name: client_encoding + value: UTF8 + - name: server_version + value: 16.1 (Debian 16.1-1.pgdg120+1) + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.240419203Z + restimestampmock: 2024-02-09T10:20:50.24047866Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-4 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.241574547Z + restimestampmock: 2024-02-09T10:20:50.241651254Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-5 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAHdTRUxFQ1QgdC5vaWQsIHR5cGFycmF5CkZST00gcGdfdHlwZSB0IEpPSU4gcGdfbmFtZXNwYWNlIG5zCiAgICBPTiB0eXBuYW1lc3BhY2UgPSBucy5vaWQKV0hFUkUgdHlwbmFtZSA9ICdoc3RvcmUnOwoA + query: + string: 'SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid WHERE typname = ''hstore''; ' + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [111, 105, 100], table_oid: 1247, table_attribute_number: 1, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}, {name: [116, 121, 112, 97, 114, 114, 97, 121], table_oid: 1247, table_attribute_number: 15, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.243360791Z + restimestampmock: 2024-02-09T10:20:50.243385416Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-6 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.244072772Z + restimestampmock: 2024-02-09T10:20:50.244098563Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-7 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.244693006Z + restimestampmock: 2024-02-09T10:20:50.244715338Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-8 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select pg_catalog.version() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAACAAAXZlcnNpb24AAAAAAAAAAAAAGf///////wAARAAAAIMAAQAAAHlQb3N0Z3JlU1FMIDE2LjEgKERlYmlhbiAxNi4xLTEucGdkZzEyMCsxKSBvbiBhYXJjaDY0LXVua25vd24tbGludXgtZ251LCBjb21waWxlZCBieSBnY2MgKERlYmlhbiAxMi4yLjAtMTQpIDEyLjIuMCwgNjQtYml0QwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [118, 101, 114, 115, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.24516216Z + restimestampmock: 2024-02-09T10:20:50.245191367Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-9 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select current_schema() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAACcAAWN1cnJlbnRfc2NoZW1hAAAAAAAAAAAAABMAQP////8AAEQAAAAQAAEAAAAGcHVibGljQwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: [public]}, {row_values: [public]}, {row_values: [public]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [99, 117, 114, 114, 101, 110, 116, 95, 115, 99, 104, 101, 109, 97], table_oid: 0, table_attribute_number: 0, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.246241214Z + restimestampmock: 2024-02-09T10:20:50.246281713Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-10 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show transaction isolation level + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAAC4AAXRyYW5zYWN0aW9uX2lzb2xhdGlvbgAAAAAAAAAAAAAZ////////AABEAAAAGAABAAAADnJlYWQgY29tbWl0dGVkQwAAAAlTSE9XAFoAAAAFVA== + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 72 + - 79 + - 87 + data_row: [{row_values: [read committed]}, {row_values: [read committed]}, {row_values: [read committed]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 95, 105, 115, 111, 108, 97, 116, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.247356559Z + restimestampmock: 2024-02-09T10:20:50.247387933Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-11 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show standard_conforming_strings + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAADQAAXN0YW5kYXJkX2NvbmZvcm1pbmdfc3RyaW5ncwAAAAAAAAAAAAAZ////////AABEAAAADAABAAAAAm9uQwAAAAlTSE9XAFoAAAAFVA== + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 72 + - 79 + - 87 + data_row: [{row_values: ["on"]}, {row_values: ["on"]}, {row_values: ["on"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 97, 110, 100, 97, 114, 100, 95, 99, 111, 110, 102, 111, 114, 109, 105, 110, 103, 95, 115, 116, 114, 105, 110, 103, 115], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.248114456Z + restimestampmock: 2024-02-09T10:20:50.24815283Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-12 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.248975766Z + restimestampmock: 2024-02-09T10:20:50.24899789Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-13 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.252045225Z + restimestampmock: 2024-02-09T10:20:50.252072266Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-14 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAYdTRUxFQ1QgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lIApGUk9NIHBnX2NhdGFsb2cucGdfY2xhc3MgSk9JTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZSBPTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5vaWQgPSBwZ19jYXRhbG9nLnBnX2NsYXNzLnJlbG5hbWVzcGFjZSAKV0hFUkUgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lID0gJ3N0dWRlbnRzJyBBTkQgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxraW5kID0gQU5ZIChBUlJBWVsncicsICdwJywgJ2YnLCAndicsICdtJ10pIEFORCBwZ19jYXRhbG9nLnBnX3RhYmxlX2lzX3Zpc2libGUocGdfY2F0YWxvZy5wZ19jbGFzcy5vaWQpIEFORCBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5uc3BuYW1lICE9ICdwZ19jYXRhbG9nJwA= + query: + string: SELECT pg_catalog.pg_class.relname FROM pg_catalog.pg_class JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.oid = pg_catalog.pg_class.relnamespace WHERE pg_catalog.pg_class.relname = 'students' AND pg_catalog.pg_class.relkind = ANY (ARRAY['r', 'p', 'f', 'v', 'm']) AND pg_catalog.pg_table_is_visible(pg_catalog.pg_class.oid) AND pg_catalog.pg_namespace.nspname != 'pg_catalog' + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAACAAAXJlbG5hbWUAAAAE6wACAAAAEwBA/////wAARAAAABIAAQAAAAhzdHVkZW50c0MAAAANU0VMRUNUIDEAWgAAAAVU + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: [students]}, {row_values: [students]}, {row_values: [students]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [114, 101, 108, 110, 97, 109, 101], table_oid: 1259, table_attribute_number: 2, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.253162445Z + restimestampmock: 2024-02-09T10:20:50.253222319Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-15 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:20:50.254107087Z + restimestampmock: 2024-02-09T10:20:50.25412767Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-16 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.542685552Z + restimestampmock: 2024-02-09T10:21:01.542714843Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-17 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAATBTRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnZXZhd2hpdGVAZXhhbXBsZS5jb20nIAogTElNSVQgMQA= + query: + string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'evawhite@example.com' LIMIT 1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.543969268Z + restimestampmock: 2024-02-09T10:21:01.544053057Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-18 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('Eva White', 'evawhite@example.com', 'sfwbxijuf222', 'Mathematics') RETURNING students."ID" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMUMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 73 + - 78 + - 83 + - 69 + - 82 + - 84 + - 32 + - 48 + - 32 + - 49 + data_row: [{row_values: ["1"]}, {row_values: ["1"]}, {row_values: ["1"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.546426702Z + restimestampmock: 2024-02-09T10:21:01.546463701Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-19 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.551006372Z + restimestampmock: 2024-02-09T10:21:01.55108062Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-20 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.552699118Z + restimestampmock: 2024-02-09T10:21:01.552721743Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-21 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDEA + query: + string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABPAAUAAAABMQAAAAlFdmEgV2hpdGUAAAAUZXZhd2hpdGVAZXhhbXBsZS5jb20AAAAMc2Z3YnhpanVmMjIyAAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.553203147Z + restimestampmock: 2024-02-09T10:21:01.553236062Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-22 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:01.556089153Z + restimestampmock: 2024-02-09T10:21:01.556110861Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-23 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.223148624Z + restimestampmock: 2024-02-09T10:21:11.223211164Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-24 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAS9TRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnam9obmRvZUBleGFtcGxlLmNvbScgCiBMSU1JVCAxAA== + query: + string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'johndoe@example.com' LIMIT 1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 48 + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.224563961Z + restimestampmock: 2024-02-09T10:21:11.224606043Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-25 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('John Doe', 'johndoe@example.com', 'skpioepf234', 'Mathematics') RETURNING students."ID" + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMkMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 73 + - 78 + - 83 + - 69 + - 82 + - 84 + - 32 + - 48 + - 32 + - 49 + data_row: [{row_values: ["2"]}, {row_values: ["2"]}, {row_values: ["2"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.226669655Z + restimestampmock: 2024-02-09T10:21:11.226748861Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-26 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 67 + - 79 + - 77 + - 77 + - 73 + - 84 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.232155218Z + restimestampmock: 2024-02-09T10:21:11.232190134Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-27 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 66 + - 69 + - 71 + - 73 + - 78 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.233212565Z + restimestampmock: 2024-02-09T10:21:11.233238147Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-28 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDIA + query: + string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 2 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABMAAUAAAABMgAAAAhKb2huIERvZQAAABNqb2huZG9lQGV4YW1wbGUuY29tAAAAC3NrcGlvZXBmMjM0AAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 83 + - 69 + - 76 + - 69 + - 67 + - 84 + - 32 + - 49 + data_row: [{row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.233889547Z + restimestampmock: 2024-02-09T10:21:11.233922754Z +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-29 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: + - 0 + - 0 + - 0 + - 0 + command_complete: + - command_tag: + - 82 + - 79 + - 76 + - 76 + - 66 + - 65 + - 67 + - 75 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-02-09T10:21:11.236845177Z + restimestampmock: 2024-02-09T10:21:11.236868259Z diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml new file mode 100755 index 0000000..e5100d2 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml @@ -0,0 +1,55 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Content-Length: "105" + Content-Type: application/json + Host: 127.0.0.1:8000 + User-Agent: curl/8.2.1 + body: |- + { + "name": "Eva White", + "email": "evawhite@example.com", + "password": "evawhite111" + } + body_type: "" + timestamp: 2024-02-09T10:21:01.532943145Z + host: "" + resp: + status_code: 200 + header: + Content-Length: "107" + Content-Type: application/json + Date: Fri, 09 Feb 2024 10:21:00 GMT + Server: uvicorn + body: '{"name":"Eva White","email":"evawhite@example.com","password":"sfwbxijuf222","stream":"Mathematics","id":1}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2024-02-09T10:21:03.574647019Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1707474063 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/students/ \ + --header 'Host: 127.0.0.1:8000' \ + --header 'User-Agent: curl/8.2.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{ + "name": "Eva White", + "email": "evawhite@example.com", + "password": "evawhite111" + }' diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml new file mode 100755 index 0000000..ecddaf6 --- /dev/null +++ b/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml @@ -0,0 +1,55 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/students/ + header: + Accept: '*/*' + Content-Length: "106" + Content-Type: application/json + Host: 127.0.0.1:8000 + User-Agent: curl/8.2.1 + body: |4- + { + "name": "John Doe", + "email": "johndoe@example.com", + "password": "johndoe123" + } + body_type: "" + timestamp: 2024-02-09T10:21:11.21894436Z + host: "" + resp: + status_code: 200 + header: + Content-Length: "104" + Content-Type: application/json + Date: Fri, 09 Feb 2024 10:21:10 GMT + Server: uvicorn + body: '{"name":"John Doe","email":"johndoe@example.com","password":"skpioepf234","stream":"Mathematics","id":2}' + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2024-02-09T10:21:13.238027535Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1707474073 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/students/ \ + --header 'User-Agent: curl/8.2.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Host: 127.0.0.1:8000' \ + --data ' { + "name": "John Doe", + "email": "johndoe@example.com", + "password": "johndoe123" + }' diff --git a/fastapi-postgres/requirements.txt b/fastapi-postgres/requirements.txt index 946ca50..5201c90 100644 --- a/fastapi-postgres/requirements.txt +++ b/fastapi-postgres/requirements.txt @@ -22,7 +22,6 @@ pydantic==2.4.2 pydantic-extra-types==2.1.0 pydantic-settings==2.0.3 pydantic_core==2.10.1 -pyscopg2==66.0.2 python-dotenv==1.0.0 python-multipart==0.0.6 PyYAML==6.0.1 @@ -34,4 +33,4 @@ ujson==5.8.0 uvicorn==0.23.2 uvloop==0.17.0 watchfiles==0.20.0 -websockets==11.0.3 \ No newline at end of file +websockets==11.0.3 From 5503b0b9c20c30c99344dc47ce1a2e2a28f88de8 Mon Sep 17 00:00:00 2001 From: Animesh pathak Date: Mon, 4 Mar 2024 06:05:20 +0000 Subject: [PATCH 10/31] fix: docker and readme instruction Signed-off-by: Animesh pathak --- django-postgres/README.md | 20 +- fastapi-postgres/README.md | 24 +- fastapi-postgres/application/database.py | 2 +- fastapi-postgres/docker-compose.yml | 16 + fastapi-postgres/keploy/test-set-0/mocks.yaml | 1567 ----------------- .../keploy/test-set-0/tests/test-1.yaml | 45 - .../keploy/test-set-0/tests/test-2.yaml | 58 - .../keploy/test-set-0/tests/test-3.yaml | 45 - .../keploy/test-set-0/tests/test-4.yaml | 45 - .../keploy/test-set-0/tests/test-5.yaml | 45 - .../keploy/test-set-0/tests/test-6.yaml | 45 - fastapi-postgres/keploy/test-set-1/mocks.yaml | 1219 ------------- .../keploy/test-set-1/tests/test-1.yaml | 55 - .../keploy/test-set-1/tests/test-2.yaml | 55 - .../keploy/testReports/report-1.yaml | 519 ------ fastapi-postgres/sql/init.sql | 4 +- fastapi-twilio/README.md | 20 +- flask-mongo/README.md | 2 +- 18 files changed, 31 insertions(+), 3755 deletions(-) delete mode 100755 fastapi-postgres/keploy/test-set-0/mocks.yaml delete mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-1.yaml delete mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-2.yaml delete mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-3.yaml delete mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-4.yaml delete mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-5.yaml delete mode 100755 fastapi-postgres/keploy/test-set-0/tests/test-6.yaml delete mode 100755 fastapi-postgres/keploy/test-set-1/mocks.yaml delete mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-1.yaml delete mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-2.yaml delete mode 100755 fastapi-postgres/keploy/testReports/report-1.yaml diff --git a/django-postgres/README.md b/django-postgres/README.md index 16d6192..91161b4 100644 --- a/django-postgres/README.md +++ b/django-postgres/README.md @@ -19,25 +19,11 @@ git clone https://github.com/keploy/samples-python.git && cd samples-python/djan Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release -**1. AMD Architecture** - -```shell -curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp - -sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy -``` - -
- 2. ARM Architecture - -```shell -curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_arm64.tar.gz" | tar xz -C /tmp - -sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +```bash + curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh + keploy ``` -
- ### Starting the PostgreSQL Instance ```bash diff --git a/fastapi-postgres/README.md b/fastapi-postgres/README.md index 888804d..d902662 100644 --- a/fastapi-postgres/README.md +++ b/fastapi-postgres/README.md @@ -20,25 +20,11 @@ pip3 install -r requirements.txt Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release -**1. AMD Architecture** - -```shell -curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp - -sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy -``` - -
- 2. ARM Architecture - -```shell -curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_arm64.tar.gz" | tar xz -C /tmp - -sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +```bash + curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh + keploy ``` -
- ### Starting the PostgreSQL Instance ```bash @@ -51,7 +37,7 @@ docker-compose up -d This command will start the recording of API calls using ebpf:- ```shell -sudo -E keploy record -c "uvicorn application.main:app --reload" +sudo -E PATH=$PATH keploy record -c "uvicorn application.main:app --reload" ``` Make API Calls using Hoppscotch, Postman or cURL command. Keploy with capture those calls to generate the test-suites containing testcases and data mocks. @@ -118,7 +104,7 @@ Now all these API calls were captured as **editable** testcases and written to ` Now let's run the application in test mode. ```shell -sudo -E keploy test -c "uvicorn application.main:app --reload" --delay 10 +sudo -E PATH=$PATH keploy test -c "uvicorn application.main:app --reload" --delay 10 ``` So, no need to setup fake database/apis like Postgres or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Postgres 😄** diff --git a/fastapi-postgres/application/database.py b/fastapi-postgres/application/database.py index 044ffb7..8b00777 100644 --- a/fastapi-postgres/application/database.py +++ b/fastapi-postgres/application/database.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker -SQLALCHEMY_DATABASE_URL = "postgresql://postgres:postgres@0.0.0.0:5432/studentdb" +SQLALCHEMY_DATABASE_URL = "postgresql://postgres:postgres@postgres:5432/studentdb" engine = create_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) diff --git a/fastapi-postgres/docker-compose.yml b/fastapi-postgres/docker-compose.yml index 8cffd1a..8ce911d 100644 --- a/fastapi-postgres/docker-compose.yml +++ b/fastapi-postgres/docker-compose.yml @@ -11,3 +11,19 @@ services: - "5432:5432" # Map the PostgreSQL port to the host machine volumes: - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql + networks: + - keploy-network + + app: + container_name: fastapi-app + image: fastapi + build: + context: . + dockerfile: Dockerfile + restart: unless-stopped + ports: + - 8000:8000 + depends_on: + - postgres + networks: + - keploy-network \ No newline at end of file diff --git a/fastapi-postgres/keploy/test-set-0/mocks.yaml b/fastapi-postgres/keploy/test-set-0/mocks.yaml deleted file mode 100755 index e1a173b..0000000 --- a/fastapi-postgres/keploy/test-set-0/mocks.yaml +++ /dev/null @@ -1,1567 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - identifier: StartupRequest - length: 8 - payload: AAAACATSFi8= - ssl_request: - is_ssl: true - auth_type: 0 - postgresresponses: - - payload: Tg== - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - identifier: StartupRequest - payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl: - auth_mechanisms: - - SCRAM-SHA-256 - msg_type: 82 - auth_type: 10 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - password_message: - password: SCRAM-SHA-256 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_continue: {data: [114, 61, 52, 74, 86, 106, 122, 74, 112, 52, 47, 119, 114, 53, 76, 107, 84, 51, 47, 80, 100, 82, 122, 65, 109, 99, 112, 117, 117, 82, 118, 49, 67, 99, 87, 86, 114, 102, 122, 72, 79, 51, 51, 82, 105, 77, 105, 105, 52, 98, 44, 115, 61, 66, 89, 47, 121, 78, 51, 75, 102, 49, 117, 90, 109, 90, 69, 100, 85, 72, 111, 68, 105, 117, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} - msg_type: 82 - auth_type: 11 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_final: {data: [118, 61, 84, 87, 72, 57, 77, 119, 88, 70, 57, 109, 51, 107, 113, 85, 71, 76, 56, 110, 52, 104, 43, 97, 50, 106, 83, 89, 55, 74, 53, 109, 97, 122, 75, 111, 77, 83, 51, 52, 53, 75, 89, 80, 107, 61]} - backend_key_data: - process_id: 33 - secret_key: 4106888949 - parameter_status: - - name: in_hot_standby - value: "off" - - name: integer_datetimes - value: "on" - - name: TimeZone - value: Etc/UTC - - name: IntervalStyle - value: postgres - - name: is_superuser - value: "on" - - name: application_name - value: "" - - name: default_transaction_read_only - value: "off" - - name: scram_iterations - value: "4096" - - name: DateStyle - value: ISO, MDY - - name: standard_conforming_strings - value: "on" - - name: session_authorization - value: postgres - - name: client_encoding - value: UTF8 - - name: server_version - value: 16.0 (Debian 16.0-1.pgdg120+1) - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: | - SELECT t.oid, typarray - FROM pg_type t JOIN pg_namespace ns - ON typnamespace = ns.oid - WHERE typname = 'hstore'; - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [111, 105, 100], table_oid: 1247, table_attribute_number: 1, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}, {name: [116, 121, 112, 97, 114, 114, 97, 121], table_oid: 1247, table_attribute_number: 15, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: select pg_catalog.version() - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{values: [[80, 111, 115, 116, 103, 114, 101, 83, 81, 76, 32, 49, 54, 46, 48, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 54, 46, 48, 45, 49, 46, 112, 103, 100, 103, 49, 50, 48, 43, 49, 41, 32, 111, 110, 32, 120, 56, 54, 95, 54, 52, 45, 112, 99, 45, 108, 105, 110, 117, 120, 45, 103, 110, 117, 44, 32, 99, 111, 109, 112, 105, 108, 101, 100, 32, 98, 121, 32, 103, 99, 99, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 50, 46, 50, 46, 48, 45, 49, 52, 41, 32, 49, 50, 46, 50, 46, 48, 44, 32, 54, 52, 45, 98, 105, 116]]}, {values: [[80, 111, 115, 116, 103, 114, 101, 83, 81, 76, 32, 49, 54, 46, 48, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 54, 46, 48, 45, 49, 46, 112, 103, 100, 103, 49, 50, 48, 43, 49, 41, 32, 111, 110, 32, 120, 56, 54, 95, 54, 52, 45, 112, 99, 45, 108, 105, 110, 117, 120, 45, 103, 110, 117, 44, 32, 99, 111, 109, 112, 105, 108, 101, 100, 32, 98, 121, 32, 103, 99, 99, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 50, 46, 50, 46, 48, 45, 49, 52, 41, 32, 49, 50, 46, 50, 46, 48, 44, 32, 54, 52, 45, 98, 105, 116]]}, {values: [[80, 111, 115, 116, 103, 114, 101, 83, 81, 76, 32, 49, 54, 46, 48, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 54, 46, 48, 45, 49, 46, 112, 103, 100, 103, 49, 50, 48, 43, 49, 41, 32, 111, 110, 32, 120, 56, 54, 95, 54, 52, 45, 112, 99, 45, 108, 105, 110, 117, 120, 45, 103, 110, 117, 44, 32, 99, 111, 109, 112, 105, 108, 101, 100, 32, 98, 121, 32, 103, 99, 99, 32, 40, 68, 101, 98, 105, 97, 110, 32, 49, 50, 46, 50, 46, 48, 45, 49, 52, 41, 32, 49, 50, 46, 50, 46, 48, 44, 32, 54, 52, 45, 98, 105, 116]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [118, 101, 114, 115, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: select current_schema() - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{values: [[112, 117, 98, 108, 105, 99]]}, {values: [[112, 117, 98, 108, 105, 99]]}, {values: [[112, 117, 98, 108, 105, 99]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [99, 117, 114, 114, 101, 110, 116, 95, 115, 99, 104, 101, 109, 97], table_oid: 0, table_attribute_number: 0, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: show transaction isolation level - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 72 - - 79 - - 87 - data_row: [{values: [[114, 101, 97, 100, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100]]}, {values: [[114, 101, 97, 100, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100]]}, {values: [[114, 101, 97, 100, 32, 99, 111, 109, 109, 105, 116, 116, 101, 100]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 95, 105, 115, 111, 108, 97, 116, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: show standard_conforming_strings - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 72 - - 79 - - 87 - data_row: [{values: [[111, 110]]}, {values: [[111, 110]]}, {values: [[111, 110]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 97, 110, 100, 97, 114, 100, 95, 99, 111, 110, 102, 111, 114, 109, 105, 110, 103, 95, 115, 116, 114, 105, 110, 103, 115], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT pg_catalog.pg_class.relname \nFROM pg_catalog.pg_class JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.oid = pg_catalog.pg_class.relnamespace \nWHERE pg_catalog.pg_class.relname = 'students' AND pg_catalog.pg_class.relkind = ANY (ARRAY['r', 'p', 'f', 'v', 'm']) AND pg_catalog.pg_table_is_visible(pg_catalog.pg_class.oid) AND pg_catalog.pg_namespace.nspname != 'pg_catalog'" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{values: [[115, 116, 117, 100, 101, 110, 116, 115]]}, {values: [[115, 116, 117, 100, 101, 110, 116, 115]]}, {values: [[115, 116, 117, 100, 101, 110, 116, 115]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [114, 101, 108, 110, 97, 109, 101], table_oid: 1259, table_attribute_number: 2, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \n LIMIT 100 OFFSET 0" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"Email\" = 'michaelbrown@example.com' \n LIMIT 1" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('Michael Brown', 'michaelbrown@example.com', 'snjdibfmcspxo:::', 'Mathematics') RETURNING students."ID" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 73 - - 78 - - 83 - - 69 - - 82 - - 84 - - 32 - - 48 - - 32 - - 49 - data_row: [{values: [[49]]}, {values: [[49]]}, {values: [[49]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT students.\"ID\", students.\"Name\", students.\"Email\", students.\"Hashed Password\", students.\"Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 1" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 11 \n LIMIT 1" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 1 \n LIMIT 1" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \n LIMIT 100 OFFSET 0" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: "SELECT students.\"ID\" AS \"students_ID\", students.\"Name\" AS \"students_Name\", students.\"Email\" AS \"students_Email\", students.\"Hashed Password\" AS \"students_Hashed Password\", students.\"Subject Stream\" AS \"students_Subject Stream\" \nFROM students \nWHERE students.\"ID\" = 1 \n LIMIT 1" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}, {values: [[49], [77, 105, 99, 104, 97, 101, 108, 32, 66, 114, 111, 119, 110], [109, 105, 99, 104, 97, 101, 108, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [115, 110, 106, 100, 105, 98, 102, 109, 99, 115, 112, 120, 111, 58, 58, 58], [77, 97, 116, 104, 101, 109, 97, 116, 105, 99, 115]]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: DELETE FROM students WHERE students."ID" = 1 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 68 - - 69 - - 76 - - 69 - - 84 - - 69 - - 32 - - 49 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - identifier: StartupRequest - payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl: - auth_mechanisms: - - SCRAM-SHA-256 - msg_type: 82 - auth_type: 10 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - password_message: - password: SCRAM-SHA-256 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_continue: {data: [114, 61, 104, 65, 52, 72, 75, 114, 50, 75, 103, 51, 111, 66, 110, 76, 108, 120, 97, 78, 113, 50, 51, 110, 97, 97, 49, 113, 98, 70, 100, 86, 48, 121, 86, 51, 115, 113, 116, 87, 116, 108, 115, 54, 73, 51, 97, 117, 83, 110, 44, 115, 61, 87, 115, 114, 48, 101, 50, 78, 57, 105, 51, 55, 51, 89, 121, 78, 105, 47, 53, 120, 100, 86, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} - msg_type: 82 - auth_type: 11 ---- -version: api.keploy.io/v1beta2 -kind: Postgres -name: mocks -spec: - metadata: {} - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_final: {data: [118, 61, 48, 107, 114, 111, 101, 115, 78, 107, 115, 108, 107, 101, 51, 100, 75, 77, 79, 85, 109, 100, 78, 57, 88, 71, 103, 78, 87, 47, 89, 118, 114, 122, 105, 80, 85, 67, 43, 71, 114, 65, 53, 47, 56, 61]} - backend_key_data: - process_id: 54 - secret_key: 1374794602 - parameter_status: - - name: in_hot_standby - value: "off" - - name: integer_datetimes - value: "on" - - name: TimeZone - value: Etc/UTC - - name: IntervalStyle - value: postgres - - name: is_superuser - value: "on" - - name: application_name - value: "" - - name: default_transaction_read_only - value: "off" - - name: scram_iterations - value: "4096" - - name: DateStyle - value: ISO, MDY - - name: standard_conforming_strings - value: "on" - - name: session_authorization - value: postgres - - name: client_encoding - value: UTF8 - - name: server_version - value: 16.0 (Debian 16.0-1.pgdg120+1) - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 \ No newline at end of file diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-1.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-1.yaml deleted file mode 100755 index df8342b..0000000 --- a/fastapi-postgres/keploy/test-set-0/tests/test-1.yaml +++ /dev/null @@ -1,45 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-1 -spec: - metadata: {} - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: 1d33acb6-386d-45d1-99db-52329895a032 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 404 - header: - Content-Length: "29" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:02 GMT - Server: uvicorn - body: '{"detail":"Data not found!!"}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - created: 1697621766 -curl: | - curl --request GET \ - --url http://127.0.0.1:8000/students/ \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'User-Agent: PostmanRuntime/7.33.0' \ - --header 'Accept: */*' \ - --header 'Postman-Token: 1d33acb6-386d-45d1-99db-52329895a032' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-2.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-2.yaml deleted file mode 100755 index 810598c..0000000 --- a/fastapi-postgres/keploy/test-set-0/tests/test-2.yaml +++ /dev/null @@ -1,58 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-2 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "121" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: aba3841e-82f1-489f-9dda-c1c3e3ef3979 - User-Agent: PostmanRuntime/7.33.0 - body: |4- - { - "name": "Michael Brown", - "email": "michaelbrown@example.com", - "password": "michaelbrown999" - } - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "119" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:07 GMT - Server: uvicorn - body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - created: 1697621770 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/students/ \ - --header 'User-Agent: PostmanRuntime/7.33.0' \ - --header 'Accept: */*' \ - --header 'Postman-Token: aba3841e-82f1-489f-9dda-c1c3e3ef3979' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'Content-Type: application/json' \ - --data ' { - "name": "Michael Brown", - "email": "michaelbrown@example.com", - "password": "michaelbrown999" - }' diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-3.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-3.yaml deleted file mode 100755 index ac81f63..0000000 --- a/fastapi-postgres/keploy/test-set-0/tests/test-3.yaml +++ /dev/null @@ -1,45 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-3 -spec: - metadata: {} - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/11 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: 4c94cd86-3b39-4fe6-ba34-df66b82fd932 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 404 - header: - Content-Length: "43" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:21 GMT - Server: uvicorn - body: '{"detail":"Student with ID=11 not found!!"}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - created: 1697621784 -curl: | - curl --request GET \ - --url http://127.0.0.1:8000/students/11 \ - --header 'Postman-Token: 4c94cd86-3b39-4fe6-ba34-df66b82fd932' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'User-Agent: PostmanRuntime/7.33.0' \ - --header 'Accept: */*' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-4.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-4.yaml deleted file mode 100755 index 2abb599..0000000 --- a/fastapi-postgres/keploy/test-set-0/tests/test-4.yaml +++ /dev/null @@ -1,45 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-4 -spec: - metadata: {} - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/1 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: b46c5b40-375c-4956-bcea-84ef922f77f4 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "119" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:25 GMT - Server: uvicorn - body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - created: 1697621789 -curl: | - curl --request GET \ - --url http://127.0.0.1:8000/students/1 \ - --header 'User-Agent: PostmanRuntime/7.33.0' \ - --header 'Accept: */*' \ - --header 'Postman-Token: b46c5b40-375c-4956-bcea-84ef922f77f4' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-5.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-5.yaml deleted file mode 100755 index dab53d3..0000000 --- a/fastapi-postgres/keploy/test-set-0/tests/test-5.yaml +++ /dev/null @@ -1,45 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-5 -spec: - metadata: {} - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: cdbe1654-026d-4eaa-a059-1f6374a0c4c7 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "121" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:31 GMT - Server: uvicorn - body: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - created: 1697621794 -curl: | - curl --request GET \ - --url http://127.0.0.1:8000/students/ \ - --header 'User-Agent: PostmanRuntime/7.33.0' \ - --header 'Accept: */*' \ - --header 'Postman-Token: cdbe1654-026d-4eaa-a059-1f6374a0c4c7' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ diff --git a/fastapi-postgres/keploy/test-set-0/tests/test-6.yaml b/fastapi-postgres/keploy/test-set-0/tests/test-6.yaml deleted file mode 100755 index c378e76..0000000 --- a/fastapi-postgres/keploy/test-set-0/tests/test-6.yaml +++ /dev/null @@ -1,45 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-6 -spec: - metadata: {} - req: - method: DELETE - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/1 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: 4eb76f24-2797-486e-bfda-188164f4611e - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "119" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:38 GMT - Server: uvicorn - body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - created: 1697621802 -curl: | - curl --request DELETE \ - --url http://127.0.0.1:8000/students/1 \ - --header 'Postman-Token: 4eb76f24-2797-486e-bfda-188164f4611e' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'User-Agent: PostmanRuntime/7.33.0' \ - --header 'Accept: */*' \ diff --git a/fastapi-postgres/keploy/test-set-1/mocks.yaml b/fastapi-postgres/keploy/test-set-1/mocks.yaml deleted file mode 100755 index 86b47c1..0000000 --- a/fastapi-postgres/keploy/test-set-1/mocks.yaml +++ /dev/null @@ -1,1219 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-0 -spec: - metadata: - type: config - postgresrequests: - - identifier: StartupRequest - length: 8 - payload: AAAACATSFi8= - ssl_request: - is_ssl: true - auth_type: 0 - postgresresponses: - - payload: Tg== - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.216898875Z - restimestampmock: 2024-02-09T10:20:50.218562705Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-1 -spec: - metadata: - type: config - postgresrequests: - - identifier: StartupRequest - payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl: - auth_mechanisms: - - SCRAM-SHA-256 - msg_type: 82 - auth_type: 10 - reqtimestampmock: 2024-02-09T10:20:50.232737784Z - restimestampmock: 2024-02-09T10:20:50.233296602Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-2 -spec: - metadata: - type: config - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - password_message: - password: SCRAM-SHA-256 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_continue: {data: [114, 61, 68, 54, 118, 109, 56, 118, 117, 82, 116, 89, 111, 116, 75, 81, 75, 86, 74, 100, 55, 47, 85, 115, 107, 90, 70, 78, 88, 79, 112, 80, 88, 84, 67, 105, 103, 86, 51, 101, 73, 90, 48, 105, 119, 117, 65, 106, 111, 83, 44, 115, 61, 117, 110, 74, 50, 122, 68, 57, 75, 121, 76, 47, 109, 83, 114, 117, 111, 102, 121, 55, 112, 84, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} - msg_type: 82 - auth_type: 11 - reqtimestampmock: 2024-02-09T10:20:50.234459113Z - restimestampmock: 2024-02-09T10:20:50.234488904Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-3 -spec: - metadata: - type: config - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_final: {data: [118, 61, 118, 48, 53, 82, 117, 66, 89, 50, 52, 51, 72, 85, 67, 97, 116, 102, 83, 55, 67, 69, 70, 43, 72, 84, 106, 89, 90, 79, 118, 115, 115, 78, 48, 56, 116, 120, 99, 48, 103, 106, 105, 119, 85, 61]} - backend_key_data: - process_id: 34 - secret_key: 4065475156 - parameter_status: - - name: in_hot_standby - value: "off" - - name: integer_datetimes - value: "on" - - name: TimeZone - value: Etc/UTC - - name: IntervalStyle - value: postgres - - name: is_superuser - value: "on" - - name: application_name - value: "" - - name: default_transaction_read_only - value: "off" - - name: scram_iterations - value: "4096" - - name: DateStyle - value: ISO, MDY - - name: standard_conforming_strings - value: "on" - - name: session_authorization - value: postgres - - name: client_encoding - value: UTF8 - - name: server_version - value: 16.1 (Debian 16.1-1.pgdg120+1) - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.240419203Z - restimestampmock: 2024-02-09T10:20:50.24047866Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-4 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.241574547Z - restimestampmock: 2024-02-09T10:20:50.241651254Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-5 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAHdTRUxFQ1QgdC5vaWQsIHR5cGFycmF5CkZST00gcGdfdHlwZSB0IEpPSU4gcGdfbmFtZXNwYWNlIG5zCiAgICBPTiB0eXBuYW1lc3BhY2UgPSBucy5vaWQKV0hFUkUgdHlwbmFtZSA9ICdoc3RvcmUnOwoA - query: - string: 'SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid WHERE typname = ''hstore''; ' - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [111, 105, 100], table_oid: 1247, table_attribute_number: 1, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}, {name: [116, 121, 112, 97, 114, 114, 97, 121], table_oid: 1247, table_attribute_number: 15, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.243360791Z - restimestampmock: 2024-02-09T10:20:50.243385416Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-6 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.244072772Z - restimestampmock: 2024-02-09T10:20:50.244098563Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-7 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.244693006Z - restimestampmock: 2024-02-09T10:20:50.244715338Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-8 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: select pg_catalog.version() - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAACAAAXZlcnNpb24AAAAAAAAAAAAAGf///////wAARAAAAIMAAQAAAHlQb3N0Z3JlU1FMIDE2LjEgKERlYmlhbiAxNi4xLTEucGdkZzEyMCsxKSBvbiBhYXJjaDY0LXVua25vd24tbGludXgtZ251LCBjb21waWxlZCBieSBnY2MgKERlYmlhbiAxMi4yLjAtMTQpIDEyLjIuMCwgNjQtYml0QwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [118, 101, 114, 115, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.24516216Z - restimestampmock: 2024-02-09T10:20:50.245191367Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-9 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: select current_schema() - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAACcAAWN1cnJlbnRfc2NoZW1hAAAAAAAAAAAAABMAQP////8AAEQAAAAQAAEAAAAGcHVibGljQwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: [public]}, {row_values: [public]}, {row_values: [public]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [99, 117, 114, 114, 101, 110, 116, 95, 115, 99, 104, 101, 109, 97], table_oid: 0, table_attribute_number: 0, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.246241214Z - restimestampmock: 2024-02-09T10:20:50.246281713Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-10 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: show transaction isolation level - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAAC4AAXRyYW5zYWN0aW9uX2lzb2xhdGlvbgAAAAAAAAAAAAAZ////////AABEAAAAGAABAAAADnJlYWQgY29tbWl0dGVkQwAAAAlTSE9XAFoAAAAFVA== - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 72 - - 79 - - 87 - data_row: [{row_values: [read committed]}, {row_values: [read committed]}, {row_values: [read committed]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 95, 105, 115, 111, 108, 97, 116, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.247356559Z - restimestampmock: 2024-02-09T10:20:50.247387933Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-11 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: show standard_conforming_strings - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAADQAAXN0YW5kYXJkX2NvbmZvcm1pbmdfc3RyaW5ncwAAAAAAAAAAAAAZ////////AABEAAAADAABAAAAAm9uQwAAAAlTSE9XAFoAAAAFVA== - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 72 - - 79 - - 87 - data_row: [{row_values: ["on"]}, {row_values: ["on"]}, {row_values: ["on"]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 97, 110, 100, 97, 114, 100, 95, 99, 111, 110, 102, 111, 114, 109, 105, 110, 103, 95, 115, 116, 114, 105, 110, 103, 115], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.248114456Z - restimestampmock: 2024-02-09T10:20:50.24815283Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-12 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.248975766Z - restimestampmock: 2024-02-09T10:20:50.24899789Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-13 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.252045225Z - restimestampmock: 2024-02-09T10:20:50.252072266Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-14 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAYdTRUxFQ1QgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lIApGUk9NIHBnX2NhdGFsb2cucGdfY2xhc3MgSk9JTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZSBPTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5vaWQgPSBwZ19jYXRhbG9nLnBnX2NsYXNzLnJlbG5hbWVzcGFjZSAKV0hFUkUgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lID0gJ3N0dWRlbnRzJyBBTkQgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxraW5kID0gQU5ZIChBUlJBWVsncicsICdwJywgJ2YnLCAndicsICdtJ10pIEFORCBwZ19jYXRhbG9nLnBnX3RhYmxlX2lzX3Zpc2libGUocGdfY2F0YWxvZy5wZ19jbGFzcy5vaWQpIEFORCBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5uc3BuYW1lICE9ICdwZ19jYXRhbG9nJwA= - query: - string: SELECT pg_catalog.pg_class.relname FROM pg_catalog.pg_class JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.oid = pg_catalog.pg_class.relnamespace WHERE pg_catalog.pg_class.relname = 'students' AND pg_catalog.pg_class.relkind = ANY (ARRAY['r', 'p', 'f', 'v', 'm']) AND pg_catalog.pg_table_is_visible(pg_catalog.pg_class.oid) AND pg_catalog.pg_namespace.nspname != 'pg_catalog' - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAACAAAXJlbG5hbWUAAAAE6wACAAAAEwBA/////wAARAAAABIAAQAAAAhzdHVkZW50c0MAAAANU0VMRUNUIDEAWgAAAAVU - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: [students]}, {row_values: [students]}, {row_values: [students]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [114, 101, 108, 110, 97, 109, 101], table_oid: 1259, table_attribute_number: 2, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.253162445Z - restimestampmock: 2024-02-09T10:20:50.253222319Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-15 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.254107087Z - restimestampmock: 2024-02-09T10:20:50.25412767Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-16 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.542685552Z - restimestampmock: 2024-02-09T10:21:01.542714843Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-17 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAATBTRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnZXZhd2hpdGVAZXhhbXBsZS5jb20nIAogTElNSVQgMQA= - query: - string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'evawhite@example.com' LIMIT 1 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.543969268Z - restimestampmock: 2024-02-09T10:21:01.544053057Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-18 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('Eva White', 'evawhite@example.com', 'sfwbxijuf222', 'Mathematics') RETURNING students."ID" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMUMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 73 - - 78 - - 83 - - 69 - - 82 - - 84 - - 32 - - 48 - - 32 - - 49 - data_row: [{row_values: ["1"]}, {row_values: ["1"]}, {row_values: ["1"]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.546426702Z - restimestampmock: 2024-02-09T10:21:01.546463701Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-19 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.551006372Z - restimestampmock: 2024-02-09T10:21:01.55108062Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-20 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.552699118Z - restimestampmock: 2024-02-09T10:21:01.552721743Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-21 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDEA - query: - string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 1 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABPAAUAAAABMQAAAAlFdmEgV2hpdGUAAAAUZXZhd2hpdGVAZXhhbXBsZS5jb20AAAAMc2Z3YnhpanVmMjIyAAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.553203147Z - restimestampmock: 2024-02-09T10:21:01.553236062Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-22 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.556089153Z - restimestampmock: 2024-02-09T10:21:01.556110861Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-23 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.223148624Z - restimestampmock: 2024-02-09T10:21:11.223211164Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-24 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAS9TRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnam9obmRvZUBleGFtcGxlLmNvbScgCiBMSU1JVCAxAA== - query: - string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'johndoe@example.com' LIMIT 1 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.224563961Z - restimestampmock: 2024-02-09T10:21:11.224606043Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-25 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('John Doe', 'johndoe@example.com', 'skpioepf234', 'Mathematics') RETURNING students."ID" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMkMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 73 - - 78 - - 83 - - 69 - - 82 - - 84 - - 32 - - 48 - - 32 - - 49 - data_row: [{row_values: ["2"]}, {row_values: ["2"]}, {row_values: ["2"]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.226669655Z - restimestampmock: 2024-02-09T10:21:11.226748861Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-26 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.232155218Z - restimestampmock: 2024-02-09T10:21:11.232190134Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-27 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.233212565Z - restimestampmock: 2024-02-09T10:21:11.233238147Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-28 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDIA - query: - string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 2 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABMAAUAAAABMgAAAAhKb2huIERvZQAAABNqb2huZG9lQGV4YW1wbGUuY29tAAAAC3NrcGlvZXBmMjM0AAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.233889547Z - restimestampmock: 2024-02-09T10:21:11.233922754Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-29 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.236845177Z - restimestampmock: 2024-02-09T10:21:11.236868259Z diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml deleted file mode 100755 index e5100d2..0000000 --- a/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml +++ /dev/null @@ -1,55 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-1 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Content-Length: "105" - Content-Type: application/json - Host: 127.0.0.1:8000 - User-Agent: curl/8.2.1 - body: |- - { - "name": "Eva White", - "email": "evawhite@example.com", - "password": "evawhite111" - } - body_type: "" - timestamp: 2024-02-09T10:21:01.532943145Z - host: "" - resp: - status_code: 200 - header: - Content-Length: "107" - Content-Type: application/json - Date: Fri, 09 Feb 2024 10:21:00 GMT - Server: uvicorn - body: '{"name":"Eva White","email":"evawhite@example.com","password":"sfwbxijuf222","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2024-02-09T10:21:03.574647019Z - objects: [] - assertions: - noise: - header.Date: [] - created: 1707474063 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/students/ \ - --header 'Host: 127.0.0.1:8000' \ - --header 'User-Agent: curl/8.2.1' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --data '{ - "name": "Eva White", - "email": "evawhite@example.com", - "password": "evawhite111" - }' diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml deleted file mode 100755 index ecddaf6..0000000 --- a/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml +++ /dev/null @@ -1,55 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-2 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Content-Length: "106" - Content-Type: application/json - Host: 127.0.0.1:8000 - User-Agent: curl/8.2.1 - body: |4- - { - "name": "John Doe", - "email": "johndoe@example.com", - "password": "johndoe123" - } - body_type: "" - timestamp: 2024-02-09T10:21:11.21894436Z - host: "" - resp: - status_code: 200 - header: - Content-Length: "104" - Content-Type: application/json - Date: Fri, 09 Feb 2024 10:21:10 GMT - Server: uvicorn - body: '{"name":"John Doe","email":"johndoe@example.com","password":"skpioepf234","stream":"Mathematics","id":2}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2024-02-09T10:21:13.238027535Z - objects: [] - assertions: - noise: - header.Date: [] - created: 1707474073 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/students/ \ - --header 'User-Agent: curl/8.2.1' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --header 'Host: 127.0.0.1:8000' \ - --data ' { - "name": "John Doe", - "email": "johndoe@example.com", - "password": "johndoe123" - }' diff --git a/fastapi-postgres/keploy/testReports/report-1.yaml b/fastapi-postgres/keploy/testReports/report-1.yaml deleted file mode 100755 index 6ec8809..0000000 --- a/fastapi-postgres/keploy/testReports/report-1.yaml +++ /dev/null @@ -1,519 +0,0 @@ -version: api.keploy.io/v1beta1 -name: report-21 -status: PASSED -success: 6 -failure: 0 -total: 6 -tests: - - kind: Http - name: report-21 - status: PASSED - started: 1697621960 - completed: 1697621960 - test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 - mock_path: "" - test_case_id: test-1 - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: 1d33acb6-386d-45d1-99db-52329895a032 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 404 - header: - Content-Length: "29" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:02 GMT - Server: uvicorn - body: '{"detail":"Data not found!!"}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - result: - status_code: - normal: true - expected: 404 - actual: 404 - headers_result: - - normal: true - expected: - key: Content-Length - value: - - "29" - actual: - key: Content-Length - value: - - "29" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Wed, 18 Oct 2023 09:36:02 GMT - actual: - key: Date - value: - - Wed, 18 Oct 2023 09:39:19 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - body_result: - - normal: true - type: JSON - expected: '{"detail":"Data not found!!"}' - actual: '{"detail":"Data not found!!"}' - dep_result: [] - - kind: Http - name: report-21 - status: PASSED - started: 1697621960 - completed: 1697621960 - test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 - mock_path: "" - test_case_id: test-2 - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "121" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: aba3841e-82f1-489f-9dda-c1c3e3ef3979 - User-Agent: PostmanRuntime/7.33.0 - body: |4- - { - "name": "Michael Brown", - "email": "michaelbrown@example.com", - "password": "michaelbrown999" - } - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "119" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:07 GMT - Server: uvicorn - body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Length - value: - - "119" - actual: - key: Content-Length - value: - - "119" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Wed, 18 Oct 2023 09:36:07 GMT - actual: - key: Date - value: - - Wed, 18 Oct 2023 09:39:19 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - body_result: - - normal: true - type: JSON - expected: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - actual: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - dep_result: [] - - kind: Http - name: report-21 - status: PASSED - started: 1697621960 - completed: 1697621960 - test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 - mock_path: "" - test_case_id: test-3 - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/11 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: 4c94cd86-3b39-4fe6-ba34-df66b82fd932 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 404 - header: - Content-Length: "43" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:21 GMT - Server: uvicorn - body: '{"detail":"Student with ID=11 not found!!"}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - result: - status_code: - normal: true - expected: 404 - actual: 404 - headers_result: - - normal: true - expected: - key: Content-Length - value: - - "43" - actual: - key: Content-Length - value: - - "43" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Wed, 18 Oct 2023 09:36:21 GMT - actual: - key: Date - value: - - Wed, 18 Oct 2023 09:39:20 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - body_result: - - normal: true - type: JSON - expected: '{"detail":"Student with ID=11 not found!!"}' - actual: '{"detail":"Student with ID=11 not found!!"}' - dep_result: [] - - kind: Http - name: report-21 - status: PASSED - started: 1697621960 - completed: 1697621960 - test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 - mock_path: "" - test_case_id: test-4 - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/1 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: b46c5b40-375c-4956-bcea-84ef922f77f4 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "119" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:25 GMT - Server: uvicorn - body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Length - value: - - "119" - actual: - key: Content-Length - value: - - "119" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Wed, 18 Oct 2023 09:36:25 GMT - actual: - key: Date - value: - - Wed, 18 Oct 2023 09:39:20 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - body_result: - - normal: true - type: JSON - expected: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - actual: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - dep_result: [] - - kind: Http - name: report-21 - status: PASSED - started: 1697621960 - completed: 1697621960 - test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 - mock_path: "" - test_case_id: test-5 - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: cdbe1654-026d-4eaa-a059-1f6374a0c4c7 - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "121" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:31 GMT - Server: uvicorn - body: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Date - value: - - Wed, 18 Oct 2023 09:36:31 GMT - actual: - key: Date - value: - - Wed, 18 Oct 2023 09:39:20 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - - normal: true - expected: - key: Content-Length - value: - - "121" - actual: - key: Content-Length - value: - - "121" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - body_result: - - normal: true - type: JSON - expected: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' - actual: '[{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}]' - dep_result: [] - - kind: Http - name: report-21 - status: PASSED - started: 1697621960 - completed: 1697621960 - test_case_path: /home/shashwat/Projects/fastapi-postgres/keploy/test-set-3 - mock_path: "" - test_case_id: test-6 - req: - method: DELETE - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/1 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Host: 127.0.0.1:8000 - Postman-Token: 4eb76f24-2797-486e-bfda-188164f4611e - User-Agent: PostmanRuntime/7.33.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "119" - Content-Type: application/json - Date: Wed, 18 Oct 2023 09:36:38 GMT - Server: uvicorn - body: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Wed, 18 Oct 2023 09:36:38 GMT - actual: - key: Date - value: - - Wed, 18 Oct 2023 09:39:20 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - - normal: true - expected: - key: Content-Length - value: - - "119" - actual: - key: Content-Length - value: - - "119" - body_result: - - normal: true - type: JSON - expected: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - actual: '{"name":"Michael Brown","email":"michaelbrown@example.com","password":"snjdibfmcspxo:::","stream":"Mathematics","id":1}' - dep_result: [] -test_set: test-set-3 diff --git a/fastapi-postgres/sql/init.sql b/fastapi-postgres/sql/init.sql index aaa55f3..c42858b 100644 --- a/fastapi-postgres/sql/init.sql +++ b/fastapi-postgres/sql/init.sql @@ -1,2 +1,2 @@ -DROP DATABASE studentdb IF EXISTS; -CREATE DATABASE studentdb; \ No newline at end of file +CREATE DATABASE studentdb; +DROP DATABASE IF EXISTS studentdb; \ No newline at end of file diff --git a/fastapi-twilio/README.md b/fastapi-twilio/README.md index 06bbc82..0afbc7e 100644 --- a/fastapi-twilio/README.md +++ b/fastapi-twilio/README.md @@ -13,25 +13,11 @@ pip3 install -r requirements.txt Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release -**1. AMD Architecture** - -```shell -curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp - -sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy -``` - -
- 2. ARM Architecture - -```shell -curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_arm64.tar.gz" | tar xz -C /tmp - -sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +```bash + curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh + keploy ``` -
- ### Get your Twilio Credentials You can get your Twilio credentials by signing in to [Twilio Console](https://console.twilio.com/). diff --git a/flask-mongo/README.md b/flask-mongo/README.md index 8080c5f..bfe5c60 100644 --- a/flask-mongo/README.md +++ b/flask-mongo/README.md @@ -1,7 +1,7 @@ This application is a simple student management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. -Usage: +### Usage: 1. Get List of Students: Retrieve a list of all students. ``` From f05aab2faccac2a915be4ae4e907a7b3d8c3e282 Mon Sep 17 00:00:00 2001 From: Animesh pathak Date: Mon, 4 Mar 2024 06:08:38 +0000 Subject: [PATCH 11/31] fix: docker and readme instruction Signed-off-by: Animesh pathak --- fastapi-postgres/README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/fastapi-postgres/README.md b/fastapi-postgres/README.md index d902662..eca7442 100644 --- a/fastapi-postgres/README.md +++ b/fastapi-postgres/README.md @@ -32,6 +32,8 @@ Keploy can be installed on Linux directly and on Windows with the help of WSL. B docker-compose up -d ``` +> Note: Update the `SQLALCHEMY_DATABASE_URL` in the `database.py` file if you want to use a keploy with docker. + ### Capture the Testcases This command will start the recording of API calls using ebpf:- From 3ba7e7ccaf7a0b4a1bdc66532746f4bdbe025319 Mon Sep 17 00:00:00 2001 From: Swapnoneel Saha <121167506+Swpn0neel@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:31:28 +0530 Subject: [PATCH 12/31] Added Flask+MongoDB app with Unit tests, Postman testcases, Keploy tests and test coverage report (#19) * Added Flask+Mongo app with unit tests, keploy tests and test coverage report Signed-off-by: Swapnoneel Saha * Added README for sample-mongo-flask-local app Signed-off-by: Swapnoneel Saha * restructured the folders Signed-off-by: Swapnoneel Saha * renamed two directories Signed-off-by: Swapnoneel Saha * merged the local and docker flask + mongo apps Signed-off-by: Swapnoneel Saha --------- Signed-off-by: Swapnoneel Saha --- flask-mongo/.coverage | Bin 0 -> 53248 bytes flask-mongo/.coveragerc | 4 + flask-mongo/Dockerfile | 4 +- flask-mongo/README.md | 642 ++---------------- flask-mongo/__pycache__/app.cpython-310.pyc | Bin 0 -> 2049 bytes .../test_app.cpython-310-pytest-8.1.1.pyc | Bin 0 -> 2471 bytes .../__pycache__/test_app.cpython-310.pyc | Bin 0 -> 2358 bytes .../test_keploy.cpython-310-pytest-8.1.1.pyc | Bin 0 -> 657 bytes flask-mongo/app.py | 80 ++- flask-mongo/docker-compose.yml | 4 +- .../reports/test-run-0/test-set-0-report.yaml | 446 ++++++++++++ .../reports/test-run-1/test-set-0-report.yaml | 446 ++++++++++++ flask-mongo/keploy/test-set-0/mocks.yaml | 319 +++++++++ .../keploy/test-set-0/tests/test-1.yaml | 66 ++ .../keploy/test-set-0/tests/test-2.yaml | 56 ++ .../keploy/test-set-0/tests/test-3.yaml | 55 ++ .../keploy/test-set-0/tests/test-4.yaml | 51 ++ flask-mongo/keploy/test-set-1/config.yaml | 167 ----- flask-mongo/keploy/test-set-1/mocks.yaml | 64 -- flask-mongo/keploy/test-set-1/test-1.yaml | 38 -- flask-mongo/keploy/test-set-1/test-2.yaml | 34 - flask-mongo/keploy/testReports/report-1.yaml | 181 ----- flask-mongo/postman_tests/delete.js | 17 + flask-mongo/postman_tests/get.js | 17 + flask-mongo/postman_tests/post.js | 14 + flask-mongo/postman_tests/put.js | 17 + flask-mongo/requirements.txt | 10 +- flask-mongo/test_app.py | 45 ++ flask-mongo/test_keploy.py | 8 + 29 files changed, 1690 insertions(+), 1095 deletions(-) create mode 100644 flask-mongo/.coverage create mode 100644 flask-mongo/.coveragerc create mode 100644 flask-mongo/__pycache__/app.cpython-310.pyc create mode 100644 flask-mongo/__pycache__/test_app.cpython-310-pytest-8.1.1.pyc create mode 100644 flask-mongo/__pycache__/test_app.cpython-310.pyc create mode 100644 flask-mongo/__pycache__/test_keploy.cpython-310-pytest-8.1.1.pyc create mode 100644 flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml create mode 100644 flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml create mode 100644 flask-mongo/keploy/test-set-0/mocks.yaml create mode 100644 flask-mongo/keploy/test-set-0/tests/test-1.yaml create mode 100644 flask-mongo/keploy/test-set-0/tests/test-2.yaml create mode 100644 flask-mongo/keploy/test-set-0/tests/test-3.yaml create mode 100644 flask-mongo/keploy/test-set-0/tests/test-4.yaml delete mode 100755 flask-mongo/keploy/test-set-1/config.yaml delete mode 100755 flask-mongo/keploy/test-set-1/mocks.yaml delete mode 100755 flask-mongo/keploy/test-set-1/test-1.yaml delete mode 100755 flask-mongo/keploy/test-set-1/test-2.yaml delete mode 100755 flask-mongo/keploy/testReports/report-1.yaml create mode 100644 flask-mongo/postman_tests/delete.js create mode 100644 flask-mongo/postman_tests/get.js create mode 100644 flask-mongo/postman_tests/post.js create mode 100644 flask-mongo/postman_tests/put.js create mode 100644 flask-mongo/test_app.py create mode 100644 flask-mongo/test_keploy.py diff --git a/flask-mongo/.coverage b/flask-mongo/.coverage new file mode 100644 index 0000000000000000000000000000000000000000..b9fdbfc3ab404e8c0cde6193a1f517351896e37a GIT binary patch literal 53248 zcmeI)+lw1j90%~3Oqw*=EK@1lxGrVSOWiKrY+Nje^+8v=V72z5RUZV?lgY{M*tw)L zlkVya-U+l#~WLOZg3PpBPbbtBc=lL1yAR)grC63GNb=@YBf6;Y2Tsf2?dEv+(mvUU%$WMcP?7G>b zE(h_BRA)xcHJYUAdiLe6>R0}X7^GZ@!|?nS!9h?9I5JbHzJ5^Gs8y<+@Ulbiw;Hk= z`SEsxD!;Kt50$T8*k7zJF6uWf#|?#f8cjP2`zxi9M$_Ltrs?qU@$H6t$!H_tUgS8! zZ^vDRQ;Vc>s5KAwnRO+*GUS(PUV7)(wf8&RVHZ-B=vgbox!8vDRNL_vQ=5>cWD4trRz-w6@Zx z;z$$9YI2WZG&|%f8FqtgAbHdvnWY$vl35=~k5D+ZVxhXeFfN?*yvAC(vcFf%7prq~ zdN1h_JTCEl-$)R=XV3*6mYr?tRV=Lz|{mp0>gh*`{pQ690f{8u|*}M z?s`$(s(&2P&k)qZZQ1eaC;e^D@nws)rQ2~-SnKRYTfSFsJ2JdfbA4~quQ|RYox1FF z=;sJN$Wcy=?@|Hz`+vhcq?w1zi{=m0Q^klB0uX=z z1Rwwb2tWV=5P$##AfRcd^1V6z$u6^#3wGm7o_+)H$#NRH{?DDu_l}gFLU#S@fBgO* z+B*aw009U<00Izz00bZa0SG`~q6G}y&}RAjf8G37qZ<|oKmY;|fB*y_009U<00Izz z00bsbz%XV@$^ZY~)Xaa(Kg^pG7$ic100bZa0SG_<0uX=z1Rwwb2u!*_#mMWWmyBQU z{8;?&%uh2p+Ilhf^PPKFf2$Vse5rKcgr5BW|832@Z~kT8o^%kz2LT8`00Izz00bZa z0SG_<0uY!2fdYL1pc_W~l*{Gm6M*>pf9=2&#EuXl009U<00Izz00bZa0SG_<0#hu& z-~Z$Ke~KFbLWckZAOHafKmY;|fB*y_0D-9xNdEu-F8}@iJ@f8Vgp42|009U<00Izz b00bZa0SG_<0+TOb81$?EMvfo&_y7L~KzQX( literal 0 HcmV?d00001 diff --git a/flask-mongo/.coveragerc b/flask-mongo/.coveragerc new file mode 100644 index 0000000..387d12b --- /dev/null +++ b/flask-mongo/.coveragerc @@ -0,0 +1,4 @@ +[run] +omit = + /usr/* +sigterm = true \ No newline at end of file diff --git a/flask-mongo/Dockerfile b/flask-mongo/Dockerfile index cbefd2c..961d93b 100644 --- a/flask-mongo/Dockerfile +++ b/flask-mongo/Dockerfile @@ -1,5 +1,5 @@ # Use the official Python image as the base image -FROM python:3.9 +FROM python:3.10.12 # Set the working directory within the container WORKDIR /app @@ -11,7 +11,7 @@ COPY . . RUN pip3 install -r requirements.txt # Expose the port that the Flask app will run on -EXPOSE 6000 +EXPOSE 5000 # Start the Flask application CMD ["python3", "app.py"] diff --git a/flask-mongo/README.md b/flask-mongo/README.md index 54bc693..2d79824 100644 --- a/flask-mongo/README.md +++ b/flask-mongo/README.md @@ -1,600 +1,102 @@ -This application is a simple student management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. +# Sample Flask+Mongo app to demo Keploy -## Table of Contents +## Clone the sample flask-mongo application -# Introduction +```bash +git clone https://github.com/keploy/samples-python.git && cd samples-python/flask-mongo-local +``` -🪄 Dive into the world of Student CRUD Apps and see how seamlessly Keploy integrated with [Flask](https://flask.palletsprojects.com/en/3.0.x/) and [MongoDB](https://www.mongodb.com/). Buckle up, it's gonna be a fun ride! 🎢 +## Install all dependencies -## Pre-Requisite 🛠️ +```bash +pip install -r requirements.txt +``` -- Install WSL (`wsl --install`) for Windows Windows. +## Start the MongoDB server -## Optional 🛠️ +```bash +sudo service mongod start +``` -- Install Colima( `brew install colima && colima start` ) for MacOS MacOs. +## Setup Keploy -## Get Started! 🎬 +Let's get started by setting up the Keploy alias with this command: -## Setup the MongoDB Database 📦 +```bash +curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh +``` -Create a docker network, run - +You should see something like this: ```bash -docker network create backend + ▓██▓▄ + ▓▓▓▓██▓█▓▄ + ████████▓▒ + ▀▓▓███▄ ▄▄ ▄ ▌ + ▄▌▌▓▓████▄ ██ ▓█▀ ▄▌▀▄ ▓▓▌▄ ▓█ ▄▌▓▓▌▄ ▌▌ ▓ + ▓█████████▌▓▓ ██▓█▄ ▓█▄▓▓ ▐█▌ ██ ▓█ █▌ ██ █▌ █▓ + ▓▓▓▓▀▀▀▀▓▓▓▓▓▓▌ ██ █▓ ▓▌▄▄ ▐█▓▄▓█▀ █▓█ ▀█▄▄█▀ █▓█ + ▓▌ ▐█▌ █▌ + ▓ + +Keploy CLI + +Available Commands: + example Example to record and test via keploy + generate-config generate the keploy configuration file + record record the keploy testcases from the API calls + test run the recorded testcases and execute assertions + update Update Keploy + +Flags: + --debug Run in debug mode + -h, --help help for keploy + -v, --version version for keploy + +Use "keploy [command] --help" for more information about a command. ``` -Start the MongoDB instance- +## Lights, Camera, Record! 🎥 + +To initiate the recording of API calls, execute this command in your terminal: ```bash -docker run -p 27017:27017 -d --network backend --name mongo mongo +keploy record -c "python3 app.py" ``` -## Clone a simple Student Management API 🧪 +Now, your app will start running, and you have to make some API calls!! + +And once you are done, you can stop the recording and give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **keploy** directory and you'll discover your handiwork in `tests` directory and `mocks.yml`. + +## Check Test Coverage + +We have a `test-app.py` where all the unit test cases has been written. Now using Keploy, we can check it's code coverage!! +Now to run your unit tests with Keploy, you can run the command given below: ```bash -git clone https://github.com/keploy/samples-python.git && cd samples-python/flask-mongo +python3 -m coverage run -p --data-file=.coverage.unit -m pytest -s test_keploy.py test_app.py ``` -## Installation 📥 - -Depending on your OS, choose your adventure: +To combine the coverage from the unit tests, and Keploy's API tests we can use the command below: --
- Linux Linux or Windows Windows +```bash +python3 -m coverage combine +``` - Alright, let's equip ourselves with the **latest Keploy binary**: +Finally, to generate the coverage report for the test run, you can run: - ```bash - curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp +```bash +python3 -m coverage report +``` - sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy - ``` +and if you want the coverage in an html file, you can run: - If everything goes right, your screen should look a bit like this: +```bash +python3 -m coverage html +``` - Moving on... -
- Run App with Docker Container Docker +## Wrapping it up 🎉 - #### Add alias for Keploy: +Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 - ```bash - alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' - ``` - - ### Lights, Camera, Record! 🎥 - - Build the app image: - - ```bash - docker build -t flask-app:1.0 . - ``` - - Capture the test-cases- - - ```shell - keploy record -c "docker run -p 6000:6000 --name flask-app --network backend flask-app:1.0" - ``` - - 🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! - - Let's make URLs short and sweet: - - ### Generate testcases - - To generate testcases we just need to **make some API calls.** - - **1. Make a POST request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **2. Make a GET request** - - ```bash - curl http://localhost:6000/students - ``` - - **3. Make a PUT request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **4. Make a GET request** - - ```bash - curl http://localhost:6000/students/12345 - ``` - - **5. Make a DELETE request** - - ```bash - curl -X DELETE http://localhost:6000/students/12345 - ``` - - Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. - - ```yaml - version: api.keploy.io/v1beta2 - kind: Http - name: test-1 - spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:6000/students - header: - Accept: "*/*" - Content-Length: "56" - Content-Type: application/json - Host: localhost:6000 - User-Agent: curl/7.81.0 - body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' - body_type: "" - timestamp: 2023-11-13T13:02:32.241333562Z - resp: - status_code: 200 - header: - Content-Length: "48" - Content-Type: application/json - Date: Mon, 13 Nov 2023 13:02:32 GMT - Server: Werkzeug/2.2.2 Python/3.9.18 - body: | - { - "message": "Student created successfully" - } - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2023-11-13T13:02:34.752123715Z - objects: [] - assertions: - noise: - - header.Date - created: 1699880554 - curl: |- - curl --request POST \ - --url http://localhost:6000/students \ - --header 'Host: localhost:6000' \ - --header 'User-Agent: curl/7.81.0' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' - ``` - - This is how `mocks.yml` generated would look like:- - - ```yaml - version: api.keploy.io/v1beta2 - kind: Mongo - name: mocks - spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' - requests: - - header: - length: 187 - requestId: 2127584089 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' - checksum: 0 - read_delay: 3469848802 - responses: - - header: - length: 166 - requestId: 154 - responseTo: 2127584089 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 869555 - created: 1699880576 - reqTimestampMock: 2023-11-13T13:02:56.385067848Z - resTimestampMock: 2023-11-13T13:02:56.386374941Z - ``` - - Want to see if everything works as expected? - - #### Run Tests - - Time to put things to the test 🧪 - - ```shell - keploy test -c "sudo docker run -p 6000:6000 --rm --network backend --name flask-app flask-app:1.0" --delay 10 - ``` - - > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. - - Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ - - ## Wrapping it up 🎉 - - Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 - - Happy coding! ✨👩‍💻👨‍💻✨ - -
-
- -
- Run App on 🐧 Linux - - We'll be running our sample application right on Linux, but just to make things a tad more thrilling, we'll have the database (PostgreSQL) chill on Docker. Ready? Let's get the party started!🎉 - - ### 📼 Roll the Tape - Recording Time! - - Install the dependencies: - - ```bash - pip install -r requirements.txt - ``` - - Now, let's Capture the test-cases- - - In `app.py`, replace the MongoDB connection URL with - `mongodb://0.0.0.0:27017/` - - Ready, set, record! Here's how: - - ```bash - keploy record -c "python3 app.py" - ``` - - Keep an eye out for the `-c `flag! It's the command charm to run the app. - - Alright, magician! With the app alive and kicking, let's weave some test cases. The spell? Making some API calls! Postman, Hoppscotch, or the classic curl - pick your wand. - - ### Generate testcases - - To generate testcases we just need to **make some API calls.** - - **1. Make a POST request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **2. Make a GET request** - - ```bash - curl http://localhost:6000/students - ``` - - **3. Make a PUT request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **4. Make a GET request** - - ```bash - curl http://localhost:6000/students/12345 - ``` - - **5. Make a DELETE request** - - ```bash - curl -X DELETE http://localhost:6000/students/12345 - ``` - - Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. - - ```yaml - version: api.keploy.io/v1beta2 - kind: Http - name: test-1 - spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:6000/students - header: - Accept: "*/*" - Content-Length: "56" - Content-Type: application/json - Host: localhost:6000 - User-Agent: curl/7.81.0 - body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' - body_type: "" - timestamp: 2023-11-13T13:02:32.241333562Z - resp: - status_code: 200 - header: - Content-Length: "48" - Content-Type: application/json - Date: Mon, 13 Nov 2023 13:02:32 GMT - Server: Werkzeug/2.2.2 Python/3.9.18 - body: | - { - "message": "Student created successfully" - } - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2023-11-13T13:02:34.752123715Z - objects: [] - assertions: - noise: - - header.Date - created: 1699880554 - curl: |- - curl --request POST \ - --url http://localhost:6000/students \ - --header 'Host: localhost:6000' \ - --header 'User-Agent: curl/7.81.0' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' - ``` - - This is how `mocks.yml` generated would look like:- - - ```yaml - version: api.keploy.io/v1beta2 - kind: Mongo - name: mocks - spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' - requests: - - header: - length: 187 - requestId: 2127584089 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' - checksum: 0 - read_delay: 3469848802 - responses: - - header: - length: 166 - requestId: 154 - responseTo: 2127584089 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 869555 - created: 1699880576 - reqTimestampMock: 2023-11-13T13:02:56.385067848Z - resTimestampMock: 2023-11-13T13:02:56.386374941Z - ``` - - Want to see if everything works as expected? - - #### Run Tests - - Time to put things to the test 🧪 - - ```shell - keploy test -c "python3 app.py" --delay 10 - ``` - - > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. - - Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ - - ## Wrapping it up 🎉 - - Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible. 😊🚀 - - Happy coding! ✨👩‍💻👨‍💻✨ -
- -
- -
- --
- MacOS MacOs - - Dive straight in, but first in case you're using **Keploy** with **Colima**, give it a gentle nudge with (`colima start`). Let's make sure it's awake and ready for action! - - ### Add alias for Keploy 🐰: - - For the sake of convenience (and a bit of Mac magic 🪄), let's set up a shortcut for Keploy: - - ### Use Keploy with Docker-Desktop - - Note: To run Keploy on MacOS through [Docker](https://docs.docker.com/desktop/release-notes/#4252) the version must be `4.25.2` or above. - - #### Creating Docker Volume - - ```bash - docker volume create --driver local --opt type=debugfs --opt device=debugfs debugfs - ``` - - ```bash - alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v debugfs:/sys/kernel/debug:rw -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' - ``` - - ### Use Keploy with Colima - - ```bash - alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' - ``` - - ### Lights, Camera, Record! 🎥 - - Build the app image: - - ```bash - docker build -t flask-app:1.0 . - ``` - - Capture the test-cases- - - ```shell - keploy record -c "docker run -p 6000:6000 --name DjangoApp --network backend --name flask-app flask-app:1.0" - ``` - - 🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! - - Let's make URLs short and sweet: - - ### Generate testcases - - To generate testcases we just need to **make some API calls.** - - **1. Make a POST request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **2. Make a GET request** - - ```bash - curl http://localhost:6000/students - ``` - - **3. Make a PUT request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **4. Make a GET request** - - ```bash - curl http://localhost:6000/students/12345 - ``` - - **5. Make a DELETE request** - - ```bash - curl -X DELETE http://localhost:6000/students/12345 - ``` - - Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. - - ```yaml - version: api.keploy.io/v1beta2 - kind: Http - name: test-1 - spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:6000/students - header: - Accept: "*/*" - Content-Length: "56" - Content-Type: application/json - Host: localhost:6000 - User-Agent: curl/7.81.0 - body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' - body_type: "" - timestamp: 2023-11-13T13:02:32.241333562Z - resp: - status_code: 200 - header: - Content-Length: "48" - Content-Type: application/json - Date: Mon, 13 Nov 2023 13:02:32 GMT - Server: Werkzeug/2.2.2 Python/3.9.18 - body: | - { - "message": "Student created successfully" - } - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2023-11-13T13:02:34.752123715Z - objects: [] - assertions: - noise: - - header.Date - created: 1699880554 - curl: |- - curl --request POST \ - --url http://localhost:6000/students \ - --header 'Host: localhost:6000' \ - --header 'User-Agent: curl/7.81.0' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' - ``` - - This is how `mocks.yml` generated would look like:- - - ```yaml - version: api.keploy.io/v1beta2 - kind: Mongo - name: mocks - spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' - requests: - - header: - length: 187 - requestId: 2127584089 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' - checksum: 0 - read_delay: 3469848802 - responses: - - header: - length: 166 - requestId: 154 - responseTo: 2127584089 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 869555 - created: 1699880576 - reqTimestampMock: 2023-11-13T13:02:56.385067848Z - resTimestampMock: 2023-11-13T13:02:56.386374941Z - ``` - - Want to see if everything works as expected? - - #### Run Tests - - Time to put things to the test 🧪 - - ```shell - keploy test -c "sudo docker run -p 6000:6000 --rm --network backend --name flask-app flask-app:1.0" --delay 10 - ``` - - > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. - - Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ - - ## Wrapping it up 🎉 - - Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 - - Happy coding! ✨👩‍💻👨‍💻✨ -
+Happy coding! ✨👩‍💻👨‍💻✨ diff --git a/flask-mongo/__pycache__/app.cpython-310.pyc b/flask-mongo/__pycache__/app.cpython-310.pyc new file mode 100644 index 0000000000000000000000000000000000000000..e502979d3897a6d6fd44c61ea39de4daa6ed4ba8 GIT binary patch literal 2049 zcmZWqOK%iM5T5SodF<@N#x@W0Tp~mmB(sDI5<&JR9+!%6NGq)Q6grG?vd3Cd{B3a{(gxtse%&<*UI}%E&@^K9`|{Wk&N*08SOTN$7`_H6iptjI^C9N@j8qPqQ1Mx8@xFny!DLo1-|%$ z1A52i@?&%P5?{9RB`aUy$LI1B{G^pH&*i7)@>PD?%2!0h&pe@0!~Su8mY?J2`Gsfb zPkYO@_~I+@*oj@^-Om&C!~{}29SNmPu&b&v>+i?J)IYDvL3J|sYgh9IpP2Gl0J1@wg zGj%4w=qmPf)#2`QIwhLEa3|!DOsQs^X>USz{R6_i=M;LsPq&;n*fgHbbS_Mt3zf=j zsI#hkN#z1qmW$AhSGVDT?No|H3*J_v6ns_vQJ(L|6rZRRcx7nDU;PH^aUk)9CL9Re zLv&4)R(TE(f?X2NBa}y^I4%j3+uV46!giz&pzIOGlmq^}p6T zMX5V!=Mh*@9krJX%g%bWSLRj1VVxAiT&T6-KEPIX`pET~C1uSL0uT?c4fjob=1dQ7 zXo6YQfG(sy^@;ya#7+@;!M^R|jqP`!ryzyInn8aTCIf(d2LHPA&GM8?oEKCBo+7orjreA`eNPTW8ft5GiDp(FS28BH%HJ{%&~k5(vjDZ-cON z8_|Kc-7)UNN82fZ{Wl*L5-c?~1b>FfJOt5W3_(NIKqh=}l7pML3VIUtF69VNJ8jt=%eCC-!)XS|5oI-D@H1}7SL!gs!g z;x%R8F-Ukj?vXtwZf+jI@ff^QUW9JUE-9fUI%GT{WhKX#x53wTS?PAa8kM|VNm#Vg z$4NO5s=X(qXcq|=*-vmtE}@NCQjCTWs_!L5_9rOCHJb(UI9_V0i)Oku@-c=?tEhO^ z&mibixKq#4p|lo&1NBT= z_Ta)YDMYVlT*yYlP|5hI{r51G@60^(WHr*lRuh|G7V6oHT{$X`IBB!iCTw^c0%Mem kJBYrz0^N$!AovUE3bc@fKwd;zHE0pEg@}Y~g|OHE0^1|^1poj5 literal 0 HcmV?d00001 diff --git a/flask-mongo/__pycache__/test_app.cpython-310-pytest-8.1.1.pyc b/flask-mongo/__pycache__/test_app.cpython-310-pytest-8.1.1.pyc new file mode 100644 index 0000000000000000000000000000000000000000..ca0d856dc4193768233b03b4fada6881d7496a87 GIT binary patch literal 2471 zcma)8PjB2r6!+L(d-iYA6xs$_SR!aym1OCK1FBF&K`4hThbBU-kgTa^l6vE{&CD!O zR_Q6dR(ydTHpiU!8t@h7$|+wV5`y=}yU8YLQJu{5y!rd)_xsKB=FMi!foJdA`#XOG zj`KG<^N$bCIuvyXhC7_3PM_GfJM>(KI77c*A!Sd{51_|Q!(rGDZJU?UVYOc!*7~*S zn0mhsWBjx+Z1$VP`N8289=vpTAc8^b$m=hNMIP?C^05deH;!R_PM+G*p{Edm)9Vo9 zv7+d>rcy8+KR4A)wwuJ8dAtW*^v7od5$g>e4tC<;|x~r)3tlgwk6~?QOD*?FtzaSabGZ-GlN3iuwwS zb|&Q5Idmd8$DuQDB3FAy==-|DU1;%-z(xVof=Ou4?7%i&Z)@Cwldi>in!=fqJnK-2 z$1rsb`$ut_h)kOhog~|pNR?T*7#$4(6N#ai&_X4osVL2)J|V_eBHcN0WDB~_HoC)1 zcjNB15>j>5J}a{Bclmyn=8S{ShD9pWYH^^S=UI0rg@dmS^K3U?P4k$gT^kKXS{%Rz zLT?vUSXH60YJ?K%wn&SN-@gLdnjLu!Iy|6-4kJUj5IhtQKtg&QSK_h|zRnBTfT}$~ zX%?`DYQZE1e*-*)tHIuPuI@b>bZL8p3PH5ne+?Cs2lrmPFD!2Z!u>YiK+H1?xno!qmA?u}li2 z_^j4tMbgCq3TYasJUjghVo}RraItnQ1=E7J)hLdIQahtGJ?I3bGW;S}+SHi>CiVBf zj#z5yK)D{ND9*VswCvf)jL(^79Zxo4S@{tdL#0qfp219neh$(_j5#W|jWDwJpkGli zHL?iQE|GEjI>48wTml+dsX(znuR~?mGCd#>UI!1rB*z3npHvRXAmHv4{>l|*sCvU+zr+`bR?exBW_ zdhe`(cXyUJO%>CI;8DU)i2M}7I9s}qWEVT3Yuwl_KtP~El;rsKxxTaZXxf1!$eS=< z-bV8Ym=0fQ&`5^3Pi& zIydRTBn#VpSjxh-NKnK71KZrBUZ-kk6lH8EqR7-D z`0VgeiuFbmVFoIDEJ$btdk6~_C_)w?LRn;3#1>+N)M|H?$35=pZmMdq zJaSgfHsS}e7%#ozH{cg~%gVoC3BkS9Gxm%fBYIr7>(=Aet#eLQJ6~9+6L|K%y}$Fj zN6263%svh{8&K3X7*04%Nf+N%N(Zz{Dc0@O8rWTX;B+11)70&{(C(z(!0-B$d{4N` zy;p>Lg7n#u-K~i__xCK>7G&HwCNPV>FePB8uny@2w6vq52&~dAA|3CRwdYYUiJ#~3 z9(1uEw)-O1&v=Z3XCDik4Jhg{7(u#}ldi=nw_cI1&28?$+o_U)6n)OX_jrxh;qCJV zZ^E1Lg%>1PESENg(wmXmdmd#`Pso@;%;|%58_E+X>MJmsjOj5sBq8kMkn~AtY5NF$ zN4wmD7Uu|T=t0dJ`)1Dsma#jVqea;1dYq>z>?z5!fJxj&+0d|l7^jKIbm^m$WIc(5 zluH+*!vSC-F_qFcPzhPON=H(k(9%&N-8mt05xUQwwg;JR$L%d8q-v}EsL0yi<@;Hh zM;!cUP^3bw6$g4Z&)PdFY*jiQrCGQn@}~`S7r%&m==-5#NPo=VKi9#_T{yw zgXWe;m=Hj-{MS%HX>j|E_0n+Gr`$QD+1{FD(j4D zxM&L{GP<$3o2VB2MJ)uYrJ?Zz)TBVKFgvKFPl>6q0GWxqjV@Ltn8l9@&gzm@1nVFrW&~$JWi|%n~$*b5+W-G5ttuF zX=)%*@58VOCQZQPE*-7D6_dG1S5QGv4JsTedLqEr)^DpQvOeuw+}uyxe`9e5LPU&g zK*Zs-DMq}Gn4$M0NYR1ckzI-M5m68K;ZnxmPt!Bi=$tk2>`pJuvW8cN;9)~?p5w~XcbZ}1DRa5s!J0VoE5tyt{S ICUyS#7tjhZUjP6A literal 0 HcmV?d00001 diff --git a/flask-mongo/__pycache__/test_keploy.cpython-310-pytest-8.1.1.pyc b/flask-mongo/__pycache__/test_keploy.cpython-310-pytest-8.1.1.pyc new file mode 100644 index 0000000000000000000000000000000000000000..f77eaa007830cece0fdc1e3edd2404b67b75e3a8 GIT binary patch literal 657 zcmYjO&x;c=6izZT?R0D_h$x<%n^c(2LGZLL3;sAs1w|KoDcL5i!)B6@WGqv*BCJ>c z1OEa4rCdGjzu-k*rgUi_@8x@syzl!GH5z3I*27;!|h{?b{L~==ExPkhSNFv3=($u838yPOiUFm2j1`et4$a#VvZY05X_5r4}TGkD403 yF_q(fa9i^ILoI{L9Vs=ww-?g6?Vh6J>U', methods=['GET']) -def get_student(student_id): - student = students_collection.find_one({'student_id': student_id}, {'_id': 0}) - return jsonify(student) - -@app.route('/students', methods=['POST']) -def create_student(): - new_student = request.json - students_collection.insert_one(new_student) - return jsonify({'message': 'Student created successfully'}) - -@app.route('/students/', methods=['PUT']) -def update_student(student_id): - updated_student = request.json - students_collection.update_one({'student_id': student_id}, {'$set': updated_student}) - return jsonify({'message': 'Student updated successfully'}) - -@app.route('/students/', methods=['DELETE']) -def delete_student(student_id): - students_collection.delete_one({'student_id': student_id}) - return jsonify({'message': 'Student deleted successfully'}) +client = MongoClient('mongodb://localhost:27017/task_manager') +db = client['task_manager'] +collection = db['tasks'] + +@app.route('/api/tasks', methods=['POST']) +def create_task(): + data = request.get_json() + task = { + 'title': data['title'], + 'description': data['description'] + } + result = collection.insert_one(task) + return jsonify({'message': 'Task created successfully', 'id': str(result.inserted_id)}), 201 + +@app.route('/api/tasks', methods=['GET']) +def get_all_tasks(): + tasks = [] + for task in collection.find(): + tasks.append({ + 'id': str(task['_id']), + 'title': task['title'], + 'description': task['description'] + }) + return jsonify({'tasks': tasks}) + +@app.route('/api/tasks/', methods=['PUT']) +def update_task(task_id): + data = request.get_json() + updated_task = { + 'title': data['title'], + 'description': data['description'] + } + try: + result = collection.update_one({'_id': ObjectId(task_id)}, {'$set': updated_task}) + if result.modified_count == 0: + return jsonify({'error': 'Task not found or no changes were made'}), 404 + else: + return jsonify({'message': 'Task updated successfully'}) + except Exception as e: + return jsonify({'error': str(e)}), 500 + +@app.route('/api/tasks/', methods=['DELETE']) +def delete_task(task_id): + collection.delete_one({'_id': ObjectId(task_id)}) + return jsonify({'message': 'Task deleted successfully'}) if __name__ == '__main__': - app.run(host='0.0.0.0', port=6000, debug=True) + app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/flask-mongo/docker-compose.yml b/flask-mongo/docker-compose.yml index 7ef7346..1d71e32 100644 --- a/flask-mongo/docker-compose.yml +++ b/flask-mongo/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3' +version: "3" services: mongo: image: mongo @@ -16,7 +16,7 @@ services: build: context: . ports: - - "6000:6000" + - "5000:5000" depends_on: - mongo networks: diff --git a/flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml b/flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml new file mode 100644 index 0000000..c4c5d3c --- /dev/null +++ b/flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml @@ -0,0 +1,446 @@ +version: api.keploy.io/v1beta1 +name: test-set-0-report +status: FAILED +success: 0 +failure: 4 +total: 4 +tests: + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873653 + completed: 1713873653 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-1 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "59" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title": "Task 6","description": "Description for Task 6"}' + timestamp: 2024-04-22T16:38:39.232565209+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "267" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:08:39 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "tasks": [ + { + "description": "should update", + "id": "6626362fc7c5eddf174c88e4", + "title": "Updated" + }, + { + "description": "Should work", + "id": "66263667c7c5eddf174c88e5", + "title": "Let's Check another time" + } + ] + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:38:41.245704918+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:08:39 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:00:53 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + - normal: false + expected: + key: Content-Length + value: + - "267" + actual: + key: Content-Length + value: + - "191" + body_result: + - normal: true + type: JSON + expected: | + { + "tasks": [ + { + "description": "should update", + "id": "6626362fc7c5eddf174c88e4", + "title": "Updated" + }, + { + "description": "Should work", + "id": "66263667c7c5eddf174c88e5", + "title": "Let's Check another time" + } + ] + } + actual: | + {"tasks":[{"description":"should update","id":"6626362fc7c5eddf174c88e4","title":"Updated"},{"description":"Should work","id":"66263667c7c5eddf174c88e5","title":"Let's Check another time"}]} + dep_result: [] + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873653 + completed: 1713873653 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-2 + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "57" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title":"Hey, let''s Check","description":"It will work"}' + timestamp: 2024-04-22T16:39:05.814517536+05:30 + resp: + status_code: 201 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "81" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:09:05 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "id": "66264551a6e962a1cbd50429", + "message": "Task created successfully" + } + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:39:07.866639952+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 201 + actual: 201 + headers_result: + - normal: false + expected: + key: Content-Length + value: + - "81" + actual: + key: Content-Length + value: + - "72" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:09:05 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:00:53 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + body_result: + - normal: false + type: JSON + expected: | + { + "id": "66264551a6e962a1cbd50429", + "message": "Task created successfully" + } + actual: | + {"id":"6627a2f5a20cac37a4bb3d0f","message":"Task created successfully"} + dep_result: [] + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873653 + completed: 1713873653 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-3 + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "53" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title": "Updated again","description": "hey there"}' + timestamp: 2024-04-22T16:39:52.181533473+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "45" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:09:52 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "message": "Task updated successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:39:54.273657454+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + - normal: false + expected: + key: Content-Length + value: + - "45" + actual: + key: Content-Length + value: + - "40" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:09:52 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:00:53 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + body_result: + - normal: true + type: JSON + expected: | + { + "message": "Task updated successfully" + } + actual: | + {"message":"Task updated successfully"} + dep_result: [] + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873653 + completed: 1713873653 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-4 + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Host: localhost:5000 + Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6 + User-Agent: PostmanRuntime/7.32.1 + body: "" + timestamp: 2024-04-22T16:40:08.615353613+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "45" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:10:08 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "message": "Task deleted successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:40:10.646676187+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + - normal: false + expected: + key: Content-Length + value: + - "45" + actual: + key: Content-Length + value: + - "40" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:10:08 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:00:53 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + body_result: + - normal: true + type: JSON + expected: | + { + "message": "Task deleted successfully" + } + actual: | + {"message":"Task deleted successfully"} + dep_result: [] +test_set: test-set-0 diff --git a/flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml b/flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml new file mode 100644 index 0000000..61157f7 --- /dev/null +++ b/flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml @@ -0,0 +1,446 @@ +version: api.keploy.io/v1beta1 +name: test-set-0-report +status: FAILED +success: 0 +failure: 4 +total: 4 +tests: + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873824 + completed: 1713873824 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-1 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "59" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title": "Task 6","description": "Description for Task 6"}' + timestamp: 2024-04-22T16:38:39.232565209+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "267" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:08:39 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "tasks": [ + { + "description": "should update", + "id": "6626362fc7c5eddf174c88e4", + "title": "Updated" + }, + { + "description": "Should work", + "id": "66263667c7c5eddf174c88e5", + "title": "Let's Check another time" + } + ] + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:38:41.245704918+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:08:39 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:03:44 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + - normal: false + expected: + key: Content-Length + value: + - "267" + actual: + key: Content-Length + value: + - "191" + body_result: + - normal: true + type: JSON + expected: | + { + "tasks": [ + { + "description": "should update", + "id": "6626362fc7c5eddf174c88e4", + "title": "Updated" + }, + { + "description": "Should work", + "id": "66263667c7c5eddf174c88e5", + "title": "Let's Check another time" + } + ] + } + actual: | + {"tasks":[{"description":"should update","id":"6626362fc7c5eddf174c88e4","title":"Updated"},{"description":"Should work","id":"66263667c7c5eddf174c88e5","title":"Let's Check another time"}]} + dep_result: [] + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873824 + completed: 1713873824 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-2 + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "57" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title":"Hey, let''s Check","description":"It will work"}' + timestamp: 2024-04-22T16:39:05.814517536+05:30 + resp: + status_code: 201 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "81" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:09:05 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "id": "66264551a6e962a1cbd50429", + "message": "Task created successfully" + } + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:39:07.866639952+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 201 + actual: 201 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:09:05 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:03:44 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + - normal: false + expected: + key: Content-Length + value: + - "81" + actual: + key: Content-Length + value: + - "72" + body_result: + - normal: false + type: JSON + expected: | + { + "id": "66264551a6e962a1cbd50429", + "message": "Task created successfully" + } + actual: | + {"id":"6627a3a0dcedca8503554d0d","message":"Task created successfully"} + dep_result: [] + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873824 + completed: 1713873824 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-3 + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "53" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title": "Updated again","description": "hey there"}' + timestamp: 2024-04-22T16:39:52.181533473+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "45" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:09:52 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "message": "Task updated successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:39:54.273657454+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:09:52 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:03:44 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + - normal: false + expected: + key: Content-Length + value: + - "45" + actual: + key: Content-Length + value: + - "40" + body_result: + - normal: true + type: JSON + expected: | + { + "message": "Task updated successfully" + } + actual: | + {"message":"Task updated successfully"} + dep_result: [] + - kind: Http + name: test-set-0 + status: FAILED + started: 1713873824 + completed: 1713873824 + test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 + mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml + test_case_id: test-4 + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Host: localhost:5000 + Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6 + User-Agent: PostmanRuntime/7.32.1 + body: "" + timestamp: 2024-04-22T16:40:08.615353613+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "45" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:10:08 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "message": "Task deleted successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:40:10.646676187+05:30 + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: false + expected: + key: Content-Length + value: + - "45" + actual: + key: Content-Length + value: + - "40" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Mon, 22 Apr 2024 11:10:08 GMT + actual: + key: Date + value: + - Tue, 23 Apr 2024 12:03:44 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + actual: + key: Server + value: + - Werkzeug/3.0.2 Python/3.10.12 + - normal: true + expected: + key: Access-Control-Allow-Origin + value: + - '*' + actual: + key: Access-Control-Allow-Origin + value: + - '*' + body_result: + - normal: true + type: JSON + expected: | + { + "message": "Task deleted successfully" + } + actual: | + {"message":"Task deleted successfully"} + dep_result: [] +test_set: test-set-0 diff --git a/flask-mongo/keploy/test-set-0/mocks.yaml b/flask-mongo/keploy/test-set-0/mocks.yaml new file mode 100644 index 0000000..8b4d319 --- /dev/null +++ b/flask-mongo/keploy/test-set-0/mocks.yaml @@ -0,0 +1,319 @@ +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-0 +spec: + metadata: + operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo","version": "4.6.3"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "5.15.146.1-microsoft-standard-WSL2"},"platform": "CPython 3.10.12.final.0"}}, returnFieldsSelector: }' + type: config + requests: + - header: + length: 283 + requestId: 1804289383 + responseTo: 0 + Opcode: 2004 + message: + flags: 0 + collection_name: admin.$cmd + number_to_skip: 0 + number_to_return: -1 + query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo","version":"4.6.3"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"5.15.146.1-microsoft-standard-WSL2"},"platform":"CPython 3.10.12.final.0"}}' + return_fields_selector: "" + responses: + - header: + length: 329 + requestId: 238 + responseTo: 1804289383 + Opcode: 1 + message: + response_flags: 8 + cursor_id: 0 + starting_from: 0 + number_returned: 1 + documents: + - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784113763"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"18"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' + read_delay: 1010011 + created: 1713784113 + reqTimestampMock: 2024-04-22T16:38:33.762559618+05:30 + resTimestampMock: 2024-04-22T16:38:33.763749062+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-1 +spec: + metadata: + operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo","version": "4.6.3"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "5.15.146.1-microsoft-standard-WSL2"},"platform": "CPython 3.10.12.final.0"},"compression": []}, returnFieldsSelector: }' + type: config + requests: + - header: + length: 301 + requestId: 1714636915 + responseTo: 0 + Opcode: 2004 + message: + flags: 0 + collection_name: admin.$cmd + number_to_skip: 0 + number_to_return: -1 + query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo","version":"4.6.3"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"5.15.146.1-microsoft-standard-WSL2"},"platform":"CPython 3.10.12.final.0"},"compression":[]}' + return_fields_selector: "" + responses: + - header: + length: 329 + requestId: 242 + responseTo: 1714636915 + Opcode: 1 + message: + response_flags: 8 + cursor_id: 0 + starting_from: 0 + number_returned: 1 + documents: + - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784119236"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"22"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' + read_delay: 527460 + created: 1713784119 + reqTimestampMock: 2024-04-22T16:38:39.236318621+05:30 + resTimestampMock: 2024-04-22T16:38:39.236994457+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-2 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"tasks","filter":{},"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }], checksum: 0 }' + requests: + - header: + length: 113 + requestId: 1957747793 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"tasks","filter":{},"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' + checksum: 0 + read_delay: 336283 + responses: + - header: + length: 272 + requestId: 243 + responseTo: 1957747793 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":{"$oid":"6626362fc7c5eddf174c88e4"},"title":"Updated","description":"should update"},{"_id":{"$oid":"66263667c7c5eddf174c88e5"},"title":"Let''s Check another time","description":"Should work"}],"id":{"$numberLong":"0"},"ns":"task_manager.tasks"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 712174 + created: 1713784119 + reqTimestampMock: 2024-04-22T16:38:39.237446806+05:30 + resTimestampMock: 2024-04-22T16:38:39.238329738+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-3 +spec: + metadata: + operation: '{ OpMsg flags: 65536, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 134 + requestId: 846930886 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 65536 + sections: + - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }' + checksum: 0 + read_delay: 2621927 + responses: + - header: + length: 313 + requestId: 244 + responseTo: 846930886 + Opcode: 2013 + message: + flagBits: 2 + sections: + - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784123771"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"18"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 10005242839 + created: 1713784123 + reqTimestampMock: 2024-04-22T16:38:33.766550283+05:30 + resTimestampMock: 2024-04-22T16:38:43.772009113+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-4 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 52 + requestId: 1714636915 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }' + checksum: 0 + read_delay: 10012944393 + responses: + - header: + length: 313 + requestId: 245 + responseTo: 1714636915 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784123781"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"19"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 458361 + created: 1713784123 + reqTimestampMock: 2024-04-22T16:38:43.781318376+05:30 + resTimestampMock: 2024-04-22T16:38:43.781975276+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-5 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 65 + requestId: 1957747793 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }' + checksum: 0 + read_delay: 10012662732 + responses: + - header: + length: 314 + requestId: 249 + responseTo: 1957747793 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784133794"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"19"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 430352 + created: 1713784133 + reqTimestampMock: 2024-04-22T16:38:53.794777057+05:30 + resTimestampMock: 2024-04-22T16:38:53.795333713+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-6 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"insert":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }, { SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"66264551a6e962a1cbd50429"},"title":"Hey, let''s Check","description":"It will work"} ] }], checksum: 0 }' + requests: + - header: + length: 207 + requestId: 596516649 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"insert":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' + - '{ SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"66264551a6e962a1cbd50429"},"title":"Hey, let''s Check","description":"It will work"} ] }' + checksum: 0 + read_delay: 26577872780 + responses: + - header: + length: 45 + requestId: 256 + responseTo: 596516649 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 5437683 + created: 1713784145 + reqTimestampMock: 2024-04-22T16:39:05.816402038+05:30 + resTimestampMock: 2024-04-22T16:39:05.822001482+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-7 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"update":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }, { SectionSingle identifier: updates , msgs: [ {"q":{"_id":{"$oid":"6626362fc7c5eddf174c88e4"}},"u":{"$set":{"title":"Updated again","description":"hey there"}},"multi":false,"upsert":false} ] }], checksum: 0 }' + requests: + - header: + length: 243 + requestId: 1102520059 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"update":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' + - '{ SectionSingle identifier: updates , msgs: [ {"q":{"_id":{"$oid":"6626362fc7c5eddf174c88e4"}},"u":{"$set":{"title":"Updated again","description":"hey there"}},"multi":false,"upsert":false} ] }' + checksum: 0 + read_delay: 46361192429 + responses: + - header: + length: 60 + requestId: 273 + responseTo: 1102520059 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"nModified":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 5673350 + created: 1713784192 + reqTimestampMock: 2024-04-22T16:39:52.183391788+05:30 + resTimestampMock: 2024-04-22T16:39:52.189223944+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-8 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"delete":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }, { SectionSingle identifier: deletes , msgs: [ {"q":{"_id":{"$oid":"66263667c7c5eddf174c88e5"}},"limit":{"$numberInt":"1"}} ] }], checksum: 0 }' + requests: + - header: + length: 166 + requestId: 1365180540 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"delete":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' + - '{ SectionSingle identifier: deletes , msgs: [ {"q":{"_id":{"$oid":"66263667c7c5eddf174c88e5"}},"limit":{"$numberInt":"1"}} ] }' + checksum: 0 + read_delay: 16427108137 + responses: + - header: + length: 45 + requestId: 286 + responseTo: 1365180540 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 1386879 + created: 1713784208 + reqTimestampMock: 2024-04-22T16:40:08.616520091+05:30 + resTimestampMock: 2024-04-22T16:40:08.61802554+05:30 diff --git a/flask-mongo/keploy/test-set-0/tests/test-1.yaml b/flask-mongo/keploy/test-set-0/tests/test-1.yaml new file mode 100644 index 0000000..fae2cc0 --- /dev/null +++ b/flask-mongo/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,66 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "59" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title": "Task 6","description": "Description for Task 6"}' + timestamp: 2024-04-22T16:38:39.232565209+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "267" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:08:39 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "tasks": [ + { + "description": "should update", + "id": "6626362fc7c5eddf174c88e4", + "title": "Updated" + }, + { + "description": "Should work", + "id": "66263667c7c5eddf174c88e5", + "title": "Let's Check another time" + } + ] + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:38:41.245704918+05:30 + objects: [] + assertions: + noise: + header.Date: [] + created: 1713784121 +curl: |- + curl --request GET \ + --url http://localhost:5000/api/tasks \ + --header 'Host: localhost:5000' \ + --header 'User-Agent: PostmanRuntime/7.32.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Connection: keep-alive' \ + --header 'Cache-Control: no-cache' \ + --header 'Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --data '{"title": "Task 6","description": "Description for Task 6"}' diff --git a/flask-mongo/keploy/test-set-0/tests/test-2.yaml b/flask-mongo/keploy/test-set-0/tests/test-2.yaml new file mode 100644 index 0000000..640154f --- /dev/null +++ b/flask-mongo/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,56 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "57" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title":"Hey, let''s Check","description":"It will work"}' + timestamp: 2024-04-22T16:39:05.814517536+05:30 + resp: + status_code: 201 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "81" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:09:05 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "id": "66264551a6e962a1cbd50429", + "message": "Task created successfully" + } + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:39:07.866639952+05:30 + objects: [] + assertions: + noise: + header.Date: [] + created: 1713784147 +curl: |- + curl --request POST \ + --url http://localhost:5000/api/tasks \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'User-Agent: PostmanRuntime/7.32.1' \ + --header 'Host: localhost:5000' \ + --header 'Cache-Control: no-cache' \ + --header 'Accept: */*' \ + --header 'Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01' \ + --header 'Content-Type: application/json' \ + --data '{"title":"Hey, let's Check","description":"It will work"}' diff --git a/flask-mongo/keploy/test-set-0/tests/test-3.yaml b/flask-mongo/keploy/test-set-0/tests/test-3.yaml new file mode 100644 index 0000000..3844c87 --- /dev/null +++ b/flask-mongo/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,55 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Content-Length: "53" + Content-Type: application/json + Host: localhost:5000 + Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3 + User-Agent: PostmanRuntime/7.32.1 + body: '{"title": "Updated again","description": "hey there"}' + timestamp: 2024-04-22T16:39:52.181533473+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "45" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:09:52 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "message": "Task updated successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:39:54.273657454+05:30 + objects: [] + assertions: + noise: + header.Date: [] + created: 1713784194 +curl: |- + curl --request PUT \ + --url http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'User-Agent: PostmanRuntime/7.32.1' \ + --header 'Host: localhost:5000' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Cache-Control: no-cache' \ + --header 'Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3' \ + --header 'Connection: keep-alive' \ + --data '{"title": "Updated again","description": "hey there"}' diff --git a/flask-mongo/keploy/test-set-0/tests/test-4.yaml b/flask-mongo/keploy/test-set-0/tests/test-4.yaml new file mode 100644 index 0000000..9888fea --- /dev/null +++ b/flask-mongo/keploy/test-set-0/tests/test-4.yaml @@ -0,0 +1,51 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-4 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Cache-Control: no-cache + Connection: keep-alive + Host: localhost:5000 + Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6 + User-Agent: PostmanRuntime/7.32.1 + body: "" + timestamp: 2024-04-22T16:40:08.615353613+05:30 + resp: + status_code: 200 + header: + Access-Control-Allow-Origin: '*' + Content-Length: "45" + Content-Type: application/json + Date: Mon, 22 Apr 2024 11:10:08 GMT + Server: Werkzeug/3.0.2 Python/3.10.12 + body: | + { + "message": "Task deleted successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-04-22T16:40:10.646676187+05:30 + objects: [] + assertions: + noise: + header.Date: [] + created: 1713784210 +curl: | + curl --request DELETE \ + --url http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Connection: keep-alive' \ + --header 'User-Agent: PostmanRuntime/7.32.1' \ + --header 'Accept: */*' \ + --header 'Cache-Control: no-cache' \ + --header 'Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6' \ + --header 'Host: localhost:5000' \ diff --git a/flask-mongo/keploy/test-set-1/config.yaml b/flask-mongo/keploy/test-set-1/config.yaml deleted file mode 100755 index e451518..0000000 --- a/flask-mongo/keploy/test-set-1/config.yaml +++ /dev/null @@ -1,167 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Mongo -name: config -spec: - metadata: - operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo","version": "4.4.1"},"os": {"type": "Linux","name": "Linux","architecture": "aarch64","version": "6.1.29-0-virt"},"platform": "CPython 3.9.17.final.0"}}, returnFieldsSelector: }' - requests: - - header: - length: 262 - requestId: 1890541915 - responseTo: 0 - Opcode: 2004 - message: - flags: 0 - collection_name: admin.$cmd - number_to_skip: 0 - number_to_return: -1 - query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo","version":"4.4.1"},"os":{"type":"Linux","name":"Linux","architecture":"aarch64","version":"6.1.29-0-virt"},"platform":"CPython 3.9.17.final.0"}}' - return_fields_selector: "" - read_delay: 82208 - responses: - - header: - length: 329 - requestId: 3 - responseTo: 1890541915 - Opcode: 1 - message: - response_flags: 8 - cursor_id: 0 - starting_from: 0 - number_returned: 1 - documents: - - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"64dcc6eb86233da4f389a58b"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1692190448932"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"1"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"17"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' - read_delay: 659750 - created: 1692190448 ---- -version: api.keploy.io/v1beta2 -kind: Mongo -name: config -spec: - metadata: - operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo","version": "4.4.1"},"os": {"type": "Linux","name": "Linux","architecture": "aarch64","version": "6.1.29-0-virt"},"platform": "CPython 3.9.17.final.0"},"compression": []}, returnFieldsSelector: }' - requests: - - header: - length: 280 - requestId: 1076681270 - responseTo: 0 - Opcode: 2004 - message: - flags: 0 - collection_name: admin.$cmd - number_to_skip: 0 - number_to_return: -1 - query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo","version":"4.4.1"},"os":{"type":"Linux","name":"Linux","architecture":"aarch64","version":"6.1.29-0-virt"},"platform":"CPython 3.9.17.final.0"},"compression":[]}' - return_fields_selector: "" - read_delay: 51917 - responses: - - header: - length: 329 - requestId: 4 - responseTo: 1076681270 - Opcode: 1 - message: - response_flags: 8 - cursor_id: 0 - starting_from: 0 - number_returned: 1 - documents: - - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"64dcc6eb86233da4f389a58b"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1692190448936"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"2"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"17"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' - read_delay: 999250 - created: 1692190448 ---- -version: api.keploy.io/v1beta2 -kind: Mongo -name: config -spec: - metadata: - operation: '{ OpMsg flags: 65536, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"64dcc6eb86233da4f389a58b"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }], checksum: 0 }' - requests: - - header: - length: 134 - requestId: 613273587 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 65536 - sections: - - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"64dcc6eb86233da4f389a58b"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }' - checksum: 0 - read_delay: 3336333 - responses: - - header: - length: 313 - requestId: 10 - responseTo: 613273587 - Opcode: 2013 - message: - flagBits: 2 - sections: - - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"64dcc6eb86233da4f389a58b"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1692190458940"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"1"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"17"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 10005077213 - created: 1692190458 ---- -version: api.keploy.io/v1beta2 -kind: Mongo -name: config -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }], checksum: 0 }' - requests: - - header: - length: 52 - requestId: 1075693109 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }' - checksum: 0 - read_delay: 10043184088 - responses: - - header: - length: 313 - requestId: 11 - responseTo: 1075693109 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"64dcc6eb86233da4f389a58b"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1692190458982"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"3"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"17"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 746417 - created: 1692190458 ---- -version: api.keploy.io/v1beta2 -kind: Mongo -name: config -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }], checksum: 0 }' - requests: - - header: - length: 65 - requestId: 1299455543 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }' - checksum: 0 - read_delay: 10042282047 - responses: - - header: - length: 314 - requestId: 15 - responseTo: 1299455543 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"64dcc6eb86233da4f389a58b"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1692190469027"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"3"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"17"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 1815417 - created: 1692190469 diff --git a/flask-mongo/keploy/test-set-1/mocks.yaml b/flask-mongo/keploy/test-set-1/mocks.yaml deleted file mode 100755 index 3051236..0000000 --- a/flask-mongo/keploy/test-set-1/mocks.yaml +++ /dev/null @@ -1,64 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Mongo -name: mocks -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"insert":"students","ordered":true,"lsid":{"id":{"$binary":{"base64":"HHvg4XLYQFWra6WjBn1j/A==","subType":"04"}}},"$db":"studentsdb"} }, { SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"64dcc6f03b29d5de7bb2ae07"},"student_id":"123","name":"Sarthak","age":{"$numberInt":"20"}} ] }], checksum: 0 }' - requests: - - header: - length: 197 - requestId: 1340074696 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"insert":"students","ordered":true,"lsid":{"id":{"$binary":{"base64":"HHvg4XLYQFWra6WjBn1j/A==","subType":"04"}}},"$db":"studentsdb"} }' - - '{ SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"64dcc6f03b29d5de7bb2ae07"},"student_id":"123","name":"Sarthak","age":{"$numberInt":"20"}} ] }' - checksum: 0 - read_delay: 566167 - responses: - - header: - length: 45 - requestId: 6 - responseTo: 1340074696 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 27458 - created: 1692190448 ---- -version: api.keploy.io/v1beta2 -kind: Mongo -name: mocks -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{},"projection":{"_id":{"$numberInt":"0"}},"lsid":{"id":{"$binary":{"base64":"HHvg4XLYQFWra6WjBn1j/A==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' - requests: - - header: - length: 140 - requestId: 1596327406 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"find":"students","filter":{},"projection":{"_id":{"$numberInt":"0"}},"lsid":{"id":{"$binary":{"base64":"HHvg4XLYQFWra6WjBn1j/A==","subType":"04"}}},"$db":"studentsdb"} }' - checksum: 0 - read_delay: 9681533921 - responses: - - header: - length: 273 - requestId: 9 - responseTo: 1596327406 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"123","name":"Sarthak","age":{"$numberInt":"20"}},{"student_id":"123","name":"Sarthak","age":{"$numberInt":"20"}},{"student_id":"123","name":"Sarthak","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 40167 - created: 1692190458 diff --git a/flask-mongo/keploy/test-set-1/test-1.yaml b/flask-mongo/keploy/test-set-1/test-1.yaml deleted file mode 100755 index 4141f28..0000000 --- a/flask-mongo/keploy/test-set-1/test-1.yaml +++ /dev/null @@ -1,38 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-1 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:6000/students - header: - Accept: '*/*' - Content-Length: "51" - Content-Type: application/json - Host: localhost:6000 - User-Agent: curl/7.77.0 - body: '{"student_id": "123", "name": "Sarthak", "age": 20}' - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "48" - Content-Type: application/json - Date: Wed, 16 Aug 2023 12:54:08 GMT - Server: Werkzeug/2.3.7 Python/3.9.17 - body: | - { - "message": "Student created successfully" - } - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - created: 1692190448 diff --git a/flask-mongo/keploy/test-set-1/test-2.yaml b/flask-mongo/keploy/test-set-1/test-2.yaml deleted file mode 100755 index 77cb4a3..0000000 --- a/flask-mongo/keploy/test-set-1/test-2.yaml +++ /dev/null @@ -1,34 +0,0 @@ -version: api.keploy.io/v1beta2 -kind: Http -name: test-2 -spec: - metadata: {} - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://localhost:6000/students - header: - Accept: '*/*' - Host: localhost:6000 - User-Agent: curl/7.77.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "224" - Content-Type: application/json - Date: Wed, 16 Aug 2023 12:54:18 GMT - Server: Werkzeug/2.3.7 Python/3.9.17 - body: "[\n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }\n]\n" - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - objects: [] - assertions: - noise: - - header.Date - - body.name - created: 1692190458 diff --git a/flask-mongo/keploy/testReports/report-1.yaml b/flask-mongo/keploy/testReports/report-1.yaml deleted file mode 100755 index 14623ce..0000000 --- a/flask-mongo/keploy/testReports/report-1.yaml +++ /dev/null @@ -1,181 +0,0 @@ -version: api.keploy.io/v1beta1 -name: report-1 -status: PASSED -success: 2 -failure: 0 -total: 2 -tests: - - kind: Http - name: report-1 - status: PASSED - started: 1692258836 - completed: 1692258836 - test_case_path: /files/keploy - mock_path: "" - test_case_id: test-1 - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://172.19.0.4:6000/students - header: - Accept: '*/*' - Content-Length: "51" - Content-Type: application/json - Host: localhost:6000 - User-Agent: curl/7.77.0 - body: '{"student_id": "123", "name": "Sarthak", "age": 20}' - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "48" - Content-Type: application/json - Date: Wed, 16 Aug 2023 12:54:08 GMT - Server: Werkzeug/2.3.7 Python/3.9.17 - body: | - { - "message": "Student created successfully" - } - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Server - value: - - Werkzeug/2.3.7 Python/3.9.17 - actual: - key: Server - value: - - Werkzeug/2.3.7 Python/3.9.17 - - normal: true - expected: - key: Content-Length - value: - - "48" - actual: - key: Content-Length - value: - - "48" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Wed, 16 Aug 2023 12:54:08 GMT - actual: - key: Date - value: - - Thu, 17 Aug 2023 07:53:56 GMT - body_result: - - normal: true - type: JSON - expected: | - { - "message": "Student created successfully" - } - actual: | - { - "message": "Student created successfully" - } - dep_result: [] - - kind: Http - name: report-1 - status: PASSED - started: 1692258836 - completed: 1692258836 - test_case_path: /files/keploy - mock_path: "" - test_case_id: test-2 - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://172.19.0.4:6000/students - header: - Accept: '*/*' - Host: localhost:6000 - User-Agent: curl/7.77.0 - body: "" - body_type: "" - resp: - status_code: 200 - header: - Content-Length: "224" - Content-Type: application/json - Date: Wed, 16 Aug 2023 12:54:18 GMT - Server: Werkzeug/2.3.7 Python/3.9.17 - body: "[\n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }\n]\n" - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - noise: - - header.Date - - body.name - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Date - value: - - Wed, 16 Aug 2023 12:54:18 GMT - actual: - key: Date - value: - - Thu, 17 Aug 2023 07:53:56 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/2.3.7 Python/3.9.17 - actual: - key: Server - value: - - Werkzeug/2.3.7 Python/3.9.17 - - normal: true - expected: - key: Content-Length - value: - - "224" - actual: - key: Content-Length - value: - - "224" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - body_result: - - normal: true - type: JSON - expected: "[\n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }\n]\n" - actual: "[\n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }, \n {\n \"age\": 20, \n \"name\": \"Sarthak\", \n \"student_id\": \"123\"\n }\n]\n" - dep_result: [] diff --git a/flask-mongo/postman_tests/delete.js b/flask-mongo/postman_tests/delete.js new file mode 100644 index 0000000..a2e8f13 --- /dev/null +++ b/flask-mongo/postman_tests/delete.js @@ -0,0 +1,17 @@ +pm.test("Status code is 200 or 404", function () { + pm.expect(pm.response.code).to.be.oneOf([200, 404]); +}); + +pm.test("Successful deletion response message", function () { + if (pm.response.code === 200) { + var jsonData = pm.response.json(); + pm.expect(jsonData.message).to.eql("Task deleted successfully"); + } +}); + +pm.test("Task not found", function () { + if (pm.response.code === 404) { + var jsonData = pm.response.json(); + pm.expect(jsonData.error).to.eql("Task not found"); + } +}); diff --git a/flask-mongo/postman_tests/get.js b/flask-mongo/postman_tests/get.js new file mode 100644 index 0000000..74b758a --- /dev/null +++ b/flask-mongo/postman_tests/get.js @@ -0,0 +1,17 @@ +pm.test("Status code is 200", function () { + pm.response.to.have.status(200); +}); + +pm.test("Response is an array", function () { + var jsonData = pm.response.json(); + pm.expect(jsonData.tasks).to.be.an("array"); +}); + +pm.test("Each task has an id, title, and description", function () { + var jsonData = pm.response.json(); + jsonData.tasks.forEach(function (task) { + pm.expect(task).to.have.property("id"); + pm.expect(task).to.have.property("title"); + pm.expect(task).to.have.property("description"); + }); +}); diff --git a/flask-mongo/postman_tests/post.js b/flask-mongo/postman_tests/post.js new file mode 100644 index 0000000..9efeeb8 --- /dev/null +++ b/flask-mongo/postman_tests/post.js @@ -0,0 +1,14 @@ +pm.test("Status code is 201", function () { + pm.response.to.have.status(201); +}); + +pm.test("Response contains task ID", function () { + var jsonData = pm.response.json(); + pm.expect(jsonData).to.have.property("id"); + pm.expect(jsonData.id).to.not.be.empty; +}); + +pm.test("Response message is correct", function () { + var jsonData = pm.response.json(); + pm.expect(jsonData.message).to.eql("Task created successfully"); +}); diff --git a/flask-mongo/postman_tests/put.js b/flask-mongo/postman_tests/put.js new file mode 100644 index 0000000..d8af377 --- /dev/null +++ b/flask-mongo/postman_tests/put.js @@ -0,0 +1,17 @@ +pm.test("Status code is 200 or 404", function () { + pm.expect(pm.response.code).to.be.oneOf([200, 404]); +}); + +pm.test("Successful update response message", function () { + if (pm.response.code === 200) { + var jsonData = pm.response.json(); + pm.expect(jsonData.message).to.eql("Task updated successfully"); + } +}); + +pm.test("Task not found or no changes made", function () { + if (pm.response.code === 404) { + var jsonData = pm.response.json(); + pm.expect(jsonData.error).to.eql("Task not found or no changes were made"); + } +}); diff --git a/flask-mongo/requirements.txt b/flask-mongo/requirements.txt index 7a03746..324ca18 100644 --- a/flask-mongo/requirements.txt +++ b/flask-mongo/requirements.txt @@ -1,4 +1,6 @@ -Flask -pymongo==4.4.1 -Flask-Cors==3.0.10 -Werkzeug==2.2.2 \ No newline at end of file +Flask==3.0.3 +Flask-Cors==4.0.0 +pymongo==4.6.3 +coverage==7.4.4 +bson==0.5.10 +keploy==2.0.0a33 \ No newline at end of file diff --git a/flask-mongo/test_app.py b/flask-mongo/test_app.py new file mode 100644 index 0000000..30cf13f --- /dev/null +++ b/flask-mongo/test_app.py @@ -0,0 +1,45 @@ +import unittest +from app import app +from unittest.mock import patch, MagicMock +import json +from bson import ObjectId + +class TestTaskManager(unittest.TestCase): + + def setUp(self): + self.app = app.test_client() + self.app.testing = True + + self.collection_mock = MagicMock() + self.patcher = patch('app.collection', self.collection_mock) + self.patcher.start() + + def tearDown(self): + self.patcher.stop() + + def test_create_task(self): + data = {'title': 'Test Task', 'description': 'This is a test task'} + response = self.app.post('/api/tasks', json=data) + self.assertEqual(response.status_code, 201) + self.assertIn(b'Task created successfully', response.data) + + def test_get_all_tasks(self): + self.collection_mock.find.return_value = [] + response = self.app.get('/api/tasks') + self.assertEqual(response.status_code, 200) + self.assertEqual(json.loads(response.data)['tasks'], []) + + def test_update_task(self): + with patch('app.ObjectId', return_value='mocked_id'): + response = self.app.put('/api/tasks/mock_id', json={'title': 'Updated Task', 'description': 'This is an updated task'}) + self.assertEqual(response.status_code, 200) + self.assertIn(b'Task updated successfully', response.data) + + def test_delete_task(self): + with patch('app.ObjectId', return_value=ObjectId()): + response = self.app.delete('/api/tasks/mock_id') + self.assertEqual(response.status_code, 200) + self.assertIn(b'Task deleted successfully', response.data) + +if __name__ == '__main__': + unittest.main() diff --git a/flask-mongo/test_keploy.py b/flask-mongo/test_keploy.py new file mode 100644 index 0000000..4ee126a --- /dev/null +++ b/flask-mongo/test_keploy.py @@ -0,0 +1,8 @@ +from keploy import run, RunOptions + +def test_keploy(): + try: + options = RunOptions(delay=15, debug=False, port=0) + except ValueError as e: + print(e) + run("python3 -m coverage run -p --data-file=.coverage.keploy app.py", options) \ No newline at end of file From c4fc91eea77d1549367bf2332ab6cb56e351fed3 Mon Sep 17 00:00:00 2001 From: Animesh Pathak <53110238+Sonichigo@users.noreply.github.com> Date: Fri, 14 Jun 2024 14:58:35 +0530 Subject: [PATCH 13/31] feat: revert for the workflow (#21) * feat: added missing steps Signed-off-by: Animesh * fix: removed uncessary lines Signed-off-by: Animesh * Update README.md --------- Signed-off-by: Animesh --- flask-mongo/README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/flask-mongo/README.md b/flask-mongo/README.md index 2d79824..8a6cd42 100644 --- a/flask-mongo/README.md +++ b/flask-mongo/README.md @@ -22,8 +22,9 @@ sudo service mongod start Let's get started by setting up the Keploy alias with this command: + ```bash -curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh +curl --silent -O -L https://keploy.io/install.sh && source install.sh ``` You should see something like this: From fb38369004278844a18a87c1682e46f8a6058e62 Mon Sep 17 00:00:00 2001 From: Animesh Pathak <53110238+Sonichigo@users.noreply.github.com> Date: Fri, 14 Jun 2024 15:22:30 +0530 Subject: [PATCH 14/31] refactor: changes revert in flask-mongo (#22) * Revert "fix: docker and readme instruction" This reverts commit f05aab2faccac2a915be4ae4e907a7b3d8c3e282. * fix: refactor flask-mongo change Signed-off-by: Animesh Pathak --------- Signed-off-by: Animesh Pathak --- fastapi-postgres/README.md | 2 - flask-mongo/Dockerfile | 6 +- flask-mongo/README.md | 643 +++++++++++++++++++++++++++++---- flask-mongo/app.py | 80 ++-- flask-mongo/docker-compose.yml | 6 +- flask-mongo/requirements.txt | 10 +- 6 files changed, 613 insertions(+), 134 deletions(-) diff --git a/fastapi-postgres/README.md b/fastapi-postgres/README.md index eca7442..d902662 100644 --- a/fastapi-postgres/README.md +++ b/fastapi-postgres/README.md @@ -32,8 +32,6 @@ Keploy can be installed on Linux directly and on Windows with the help of WSL. B docker-compose up -d ``` -> Note: Update the `SQLALCHEMY_DATABASE_URL` in the `database.py` file if you want to use a keploy with docker. - ### Capture the Testcases This command will start the recording of API calls using ebpf:- diff --git a/flask-mongo/Dockerfile b/flask-mongo/Dockerfile index 961d93b..f892efb 100644 --- a/flask-mongo/Dockerfile +++ b/flask-mongo/Dockerfile @@ -1,5 +1,5 @@ # Use the official Python image as the base image -FROM python:3.10.12 +FROM python:3.9 # Set the working directory within the container WORKDIR /app @@ -11,7 +11,7 @@ COPY . . RUN pip3 install -r requirements.txt # Expose the port that the Flask app will run on -EXPOSE 5000 +EXPOSE 6000 # Start the Flask application -CMD ["python3", "app.py"] +CMD ["python3", "app.py"] \ No newline at end of file diff --git a/flask-mongo/README.md b/flask-mongo/README.md index 8a6cd42..526fad3 100644 --- a/flask-mongo/README.md +++ b/flask-mongo/README.md @@ -1,103 +1,600 @@ -# Sample Flask+Mongo app to demo Keploy +This application is a simple student management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. -## Clone the sample flask-mongo application +## Table of Contents -```bash -git clone https://github.com/keploy/samples-python.git && cd samples-python/flask-mongo-local -``` - -## Install all dependencies +# Introduction -```bash -pip install -r requirements.txt -``` +🪄 Dive into the world of Student CRUD Apps and see how seamlessly Keploy integrated with [Flask](https://flask.palletsprojects.com/en/3.0.x/) and [MongoDB](https://www.mongodb.com/). Buckle up, it's gonna be a fun ride! 🎢 -## Start the MongoDB server +## Pre-Requisite 🛠️ -```bash -sudo service mongod start -``` +- Install WSL (`wsl --install`) for Windows Windows. -## Setup Keploy +## Optional 🛠️ -Let's get started by setting up the Keploy alias with this command: +- Install Colima( `brew install colima && colima start` ) for MacOS MacOs. +## Get Started! 🎬 -```bash -curl --silent -O -L https://keploy.io/install.sh && source install.sh -``` +## Setup the MongoDB Database 📦 -You should see something like this: +Create a docker network, run - ```bash - ▓██▓▄ - ▓▓▓▓██▓█▓▄ - ████████▓▒ - ▀▓▓███▄ ▄▄ ▄ ▌ - ▄▌▌▓▓████▄ ██ ▓█▀ ▄▌▀▄ ▓▓▌▄ ▓█ ▄▌▓▓▌▄ ▌▌ ▓ - ▓█████████▌▓▓ ██▓█▄ ▓█▄▓▓ ▐█▌ ██ ▓█ █▌ ██ █▌ █▓ - ▓▓▓▓▀▀▀▀▓▓▓▓▓▓▌ ██ █▓ ▓▌▄▄ ▐█▓▄▓█▀ █▓█ ▀█▄▄█▀ █▓█ - ▓▌ ▐█▌ █▌ - ▓ - -Keploy CLI - -Available Commands: - example Example to record and test via keploy - generate-config generate the keploy configuration file - record record the keploy testcases from the API calls - test run the recorded testcases and execute assertions - update Update Keploy - -Flags: - --debug Run in debug mode - -h, --help help for keploy - -v, --version version for keploy - -Use "keploy [command] --help" for more information about a command. +docker network create backend ``` -## Lights, Camera, Record! 🎥 - -To initiate the recording of API calls, execute this command in your terminal: +Start the MongoDB instance- ```bash -keploy record -c "python3 app.py" +docker run -p 27017:27017 -d --network backend --name mongo mongo ``` -Now, your app will start running, and you have to make some API calls!! - -And once you are done, you can stop the recording and give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **keploy** directory and you'll discover your handiwork in `tests` directory and `mocks.yml`. - -## Check Test Coverage - -We have a `test-app.py` where all the unit test cases has been written. Now using Keploy, we can check it's code coverage!! -Now to run your unit tests with Keploy, you can run the command given below: +## Clone a simple Student Management API 🧪 ```bash -python3 -m coverage run -p --data-file=.coverage.unit -m pytest -s test_keploy.py test_app.py +git clone https://github.com/keploy/samples-python.git && cd samples-python/flask-mongo ``` -To combine the coverage from the unit tests, and Keploy's API tests we can use the command below: +## Installation 📥 -```bash -python3 -m coverage combine -``` +Depending on your OS, choose your adventure: -Finally, to generate the coverage report for the test run, you can run: +-
+ Linux Linux or Windows Windows -```bash -python3 -m coverage report -``` + Alright, let's equip ourselves with the **latest Keploy binary**: -and if you want the coverage in an html file, you can run: + ```bash + curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp -```bash -python3 -m coverage html -``` + sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy + ``` + + If everything goes right, your screen should look a bit like this: -## Wrapping it up 🎉 + Moving on... +
+ Run App with Docker Container Docker -Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 + #### Add alias for Keploy: -Happy coding! ✨👩‍💻👨‍💻✨ + ```bash + alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' + ``` + + ### Lights, Camera, Record! 🎥 + + Build the app image: + + ```bash + docker build -t flask-app:1.0 . + ``` + + Capture the test-cases- + + ```shell + keploy record -c "docker run -p 6000:6000 --name flask-app --network backend flask-app:1.0" + ``` + + 🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! + + Let's make URLs short and sweet: + + ### Generate testcases + + To generate testcases we just need to **make some API calls.** + + **1. Make a POST request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **2. Make a GET request** + + ```bash + curl http://localhost:6000/students + ``` + + **3. Make a PUT request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **4. Make a GET request** + + ```bash + curl http://localhost:6000/students/12345 + ``` + + **5. Make a DELETE request** + + ```bash + curl -X DELETE http://localhost:6000/students/12345 + ``` + + Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. + + ```yaml + version: api.keploy.io/v1beta2 + kind: Http + name: test-1 + spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:6000/students + header: + Accept: "*/*" + Content-Length: "56" + Content-Type: application/json + Host: localhost:6000 + User-Agent: curl/7.81.0 + body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' + body_type: "" + timestamp: 2023-11-13T13:02:32.241333562Z + resp: + status_code: 200 + header: + Content-Length: "48" + Content-Type: application/json + Date: Mon, 13 Nov 2023 13:02:32 GMT + Server: Werkzeug/2.2.2 Python/3.9.18 + body: | + { + "message": "Student created successfully" + } + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-13T13:02:34.752123715Z + objects: [] + assertions: + noise: + - header.Date + created: 1699880554 + curl: |- + curl --request POST \ + --url http://localhost:6000/students \ + --header 'Host: localhost:6000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' + ``` + + This is how `mocks.yml` generated would look like:- + + ```yaml + version: api.keploy.io/v1beta2 + kind: Mongo + name: mocks + spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' + requests: + - header: + length: 187 + requestId: 2127584089 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' + checksum: 0 + read_delay: 3469848802 + responses: + - header: + length: 166 + requestId: 154 + responseTo: 2127584089 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 869555 + created: 1699880576 + reqTimestampMock: 2023-11-13T13:02:56.385067848Z + resTimestampMock: 2023-11-13T13:02:56.386374941Z + ``` + + Want to see if everything works as expected? + + #### Run Tests + + Time to put things to the test 🧪 + + ```shell + keploy test -c "sudo docker run -p 6000:6000 --rm --network backend --name flask-app flask-app:1.0" --delay 10 + ``` + + > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. + + Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ + + ## Wrapping it up 🎉 + + Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 + + Happy coding! ✨👩‍💻👨‍💻✨ + +
+
+ +
+ Run App on 🐧 Linux + + We'll be running our sample application right on Linux, but just to make things a tad more thrilling, we'll have the database (PostgreSQL) chill on Docker. Ready? Let's get the party started!🎉 + + ### 📼 Roll the Tape - Recording Time! + + Install the dependencies: + + ```bash + pip install -r requirements.txt + ``` + + Now, let's Capture the test-cases- + + In `app.py`, replace the MongoDB connection URL with - `mongodb://0.0.0.0:27017/` + + Ready, set, record! Here's how: + + ```bash + keploy record -c "python3 app.py" + ``` + + Keep an eye out for the `-c `flag! It's the command charm to run the app. + + Alright, magician! With the app alive and kicking, let's weave some test cases. The spell? Making some API calls! Postman, Hoppscotch, or the classic curl - pick your wand. + + ### Generate testcases + + To generate testcases we just need to **make some API calls.** + + **1. Make a POST request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **2. Make a GET request** + + ```bash + curl http://localhost:6000/students + ``` + + **3. Make a PUT request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **4. Make a GET request** + + ```bash + curl http://localhost:6000/students/12345 + ``` + + **5. Make a DELETE request** + + ```bash + curl -X DELETE http://localhost:6000/students/12345 + ``` + + Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. + + ```yaml + version: api.keploy.io/v1beta2 + kind: Http + name: test-1 + spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:6000/students + header: + Accept: "*/*" + Content-Length: "56" + Content-Type: application/json + Host: localhost:6000 + User-Agent: curl/7.81.0 + body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' + body_type: "" + timestamp: 2023-11-13T13:02:32.241333562Z + resp: + status_code: 200 + header: + Content-Length: "48" + Content-Type: application/json + Date: Mon, 13 Nov 2023 13:02:32 GMT + Server: Werkzeug/2.2.2 Python/3.9.18 + body: | + { + "message": "Student created successfully" + } + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-13T13:02:34.752123715Z + objects: [] + assertions: + noise: + - header.Date + created: 1699880554 + curl: |- + curl --request POST \ + --url http://localhost:6000/students \ + --header 'Host: localhost:6000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' + ``` + + This is how `mocks.yml` generated would look like:- + + ```yaml + version: api.keploy.io/v1beta2 + kind: Mongo + name: mocks + spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' + requests: + - header: + length: 187 + requestId: 2127584089 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' + checksum: 0 + read_delay: 3469848802 + responses: + - header: + length: 166 + requestId: 154 + responseTo: 2127584089 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 869555 + created: 1699880576 + reqTimestampMock: 2023-11-13T13:02:56.385067848Z + resTimestampMock: 2023-11-13T13:02:56.386374941Z + ``` + + Want to see if everything works as expected? + + #### Run Tests + + Time to put things to the test 🧪 + + ```shell + keploy test -c "python3 app.py" --delay 10 + ``` + + > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. + + Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ + + ## Wrapping it up 🎉 + + Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible. 😊🚀 + + Happy coding! ✨👩‍💻👨‍💻✨ +
+ +
+ +
+ +-
+ MacOS MacOs + + Dive straight in, but first in case you're using **Keploy** with **Colima**, give it a gentle nudge with (`colima start`). Let's make sure it's awake and ready for action! + + ### Add alias for Keploy 🐰: + + For the sake of convenience (and a bit of Mac magic 🪄), let's set up a shortcut for Keploy: + + ### Use Keploy with Docker-Desktop + + Note: To run Keploy on MacOS through [Docker](https://docs.docker.com/desktop/release-notes/#4252) the version must be `4.25.2` or above. + + #### Creating Docker Volume + + ```bash + docker volume create --driver local --opt type=debugfs --opt device=debugfs debugfs + ``` + + ```bash + alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v debugfs:/sys/kernel/debug:rw -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' + ``` + + ### Use Keploy with Colima + + ```bash + alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' + ``` + + ### Lights, Camera, Record! 🎥 + + Build the app image: + + ```bash + docker build -t flask-app:1.0 . + ``` + + Capture the test-cases- + + ```shell + keploy record -c "docker run -p 6000:6000 --name DjangoApp --network backend --name flask-app flask-app:1.0" + ``` + + 🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! + + Let's make URLs short and sweet: + + ### Generate testcases + + To generate testcases we just need to **make some API calls.** + + **1. Make a POST request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **2. Make a GET request** + + ```bash + curl http://localhost:6000/students + ``` + + **3. Make a PUT request** + + ```bash + curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ``` + + **4. Make a GET request** + + ```bash + curl http://localhost:6000/students/12345 + ``` + + **5. Make a DELETE request** + + ```bash + curl -X DELETE http://localhost:6000/students/12345 + ``` + + Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. + + ```yaml + version: api.keploy.io/v1beta2 + kind: Http + name: test-1 + spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:6000/students + header: + Accept: "*/*" + Content-Length: "56" + Content-Type: application/json + Host: localhost:6000 + User-Agent: curl/7.81.0 + body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' + body_type: "" + timestamp: 2023-11-13T13:02:32.241333562Z + resp: + status_code: 200 + header: + Content-Length: "48" + Content-Type: application/json + Date: Mon, 13 Nov 2023 13:02:32 GMT + Server: Werkzeug/2.2.2 Python/3.9.18 + body: | + { + "message": "Student created successfully" + } + body_type: "" + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 2023-11-13T13:02:34.752123715Z + objects: [] + assertions: + noise: + - header.Date + created: 1699880554 + curl: |- + curl --request POST \ + --url http://localhost:6000/students \ + --header 'Host: localhost:6000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' + ``` + + This is how `mocks.yml` generated would look like:- + + ```yaml + version: api.keploy.io/v1beta2 + kind: Mongo + name: mocks + spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' + requests: + - header: + length: 187 + requestId: 2127584089 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' + checksum: 0 + read_delay: 3469848802 + responses: + - header: + length: 166 + requestId: 154 + responseTo: 2127584089 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 869555 + created: 1699880576 + reqTimestampMock: 2023-11-13T13:02:56.385067848Z + resTimestampMock: 2023-11-13T13:02:56.386374941Z + ``` + + Want to see if everything works as expected? + + #### Run Tests + + Time to put things to the test 🧪 + + ```shell + keploy test -c "sudo docker run -p 6000:6000 --rm --network backend --name flask-app flask-app:1.0" --delay 10 + ``` + + > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. + + Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ + + ## Wrapping it up 🎉 + + Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 + + Happy coding! ✨👩‍💻👨‍💻✨ +
\ No newline at end of file diff --git a/flask-mongo/app.py b/flask-mongo/app.py index 730db9f..9e88224 100644 --- a/flask-mongo/app.py +++ b/flask-mongo/app.py @@ -1,56 +1,42 @@ from flask import Flask, request, jsonify from pymongo import MongoClient from flask_cors import CORS -from bson import ObjectId +import collections.abc app = Flask(__name__) cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) -client = MongoClient('mongodb://localhost:27017/task_manager') -db = client['task_manager'] -collection = db['tasks'] - -@app.route('/api/tasks', methods=['POST']) -def create_task(): - data = request.get_json() - task = { - 'title': data['title'], - 'description': data['description'] - } - result = collection.insert_one(task) - return jsonify({'message': 'Task created successfully', 'id': str(result.inserted_id)}), 201 - -@app.route('/api/tasks', methods=['GET']) -def get_all_tasks(): - tasks = [] - for task in collection.find(): - tasks.append({ - 'id': str(task['_id']), - 'title': task['title'], - 'description': task['description'] - }) - return jsonify({'tasks': tasks}) - -@app.route('/api/tasks/', methods=['PUT']) -def update_task(task_id): - data = request.get_json() - updated_task = { - 'title': data['title'], - 'description': data['description'] - } - try: - result = collection.update_one({'_id': ObjectId(task_id)}, {'$set': updated_task}) - if result.modified_count == 0: - return jsonify({'error': 'Task not found or no changes were made'}), 404 - else: - return jsonify({'message': 'Task updated successfully'}) - except Exception as e: - return jsonify({'error': str(e)}), 500 - -@app.route('/api/tasks/', methods=['DELETE']) -def delete_task(task_id): - collection.delete_one({'_id': ObjectId(task_id)}) - return jsonify({'message': 'Task deleted successfully'}) +# Connect to MongoDB +client = MongoClient('mongodb://mongo:27017/') +db = client['studentsdb'] +students_collection = db['students'] + +@app.route('/students', methods=['GET']) +def get_students(): + students = list(students_collection.find({}, {'_id': 0})) + return jsonify(students) + +@app.route('/students/', methods=['GET']) +def get_student(student_id): + student = students_collection.find_one({'student_id': student_id}, {'_id': 0}) + return jsonify(student) + +@app.route('/students', methods=['POST']) +def create_student(): + new_student = request.json + students_collection.insert_one(new_student) + return jsonify({'message': 'Student created successfully'}) + +@app.route('/students/', methods=['PUT']) +def update_student(student_id): + updated_student = request.json + students_collection.update_one({'student_id': student_id}, {'$set': updated_student}) + return jsonify({'message': 'Student updated successfully'}) + +@app.route('/students/', methods=['DELETE']) +def delete_student(student_id): + students_collection.delete_one({'student_id': student_id}) + return jsonify({'message': 'Student deleted successfully'}) if __name__ == '__main__': - app.run(host='0.0.0.0', port=5000, debug=True) + app.run(host='0.0.0.0', port=6000, debug=True) \ No newline at end of file diff --git a/flask-mongo/docker-compose.yml b/flask-mongo/docker-compose.yml index 1d71e32..2970065 100644 --- a/flask-mongo/docker-compose.yml +++ b/flask-mongo/docker-compose.yml @@ -1,4 +1,4 @@ -version: "3" +version: '3' services: mongo: image: mongo @@ -16,7 +16,7 @@ services: build: context: . ports: - - "5000:5000" + - "6000:6000" depends_on: - mongo networks: @@ -26,4 +26,4 @@ networks: backend: external: true volumes: - data: + data: \ No newline at end of file diff --git a/flask-mongo/requirements.txt b/flask-mongo/requirements.txt index 324ca18..7a03746 100644 --- a/flask-mongo/requirements.txt +++ b/flask-mongo/requirements.txt @@ -1,6 +1,4 @@ -Flask==3.0.3 -Flask-Cors==4.0.0 -pymongo==4.6.3 -coverage==7.4.4 -bson==0.5.10 -keploy==2.0.0a33 \ No newline at end of file +Flask +pymongo==4.4.1 +Flask-Cors==3.0.10 +Werkzeug==2.2.2 \ No newline at end of file From 7e0e92e05c1bf42955ff34d7d5b255695b8ab0bb Mon Sep 17 00:00:00 2001 From: Swapnoneel Saha <121167506+Swpn0neel@users.noreply.github.com> Date: Tue, 18 Jun 2024 16:02:14 +0530 Subject: [PATCH 15/31] Updated README (#20) * Updated README Signed-off-by: Swapnoneel Saha * added images Signed-off-by: Swapnoneel Saha * fixed README issues Signed-off-by: Swapnoneel Saha --------- Signed-off-by: Swapnoneel Saha --- .github/License-Apache_2.0-blue.svg | 1 + .github/slack.svg | 20 ++++++++++++++++ README.md | 37 ++++++++++++++++------------- 3 files changed, 42 insertions(+), 16 deletions(-) create mode 100644 .github/License-Apache_2.0-blue.svg create mode 100644 .github/slack.svg diff --git a/.github/License-Apache_2.0-blue.svg b/.github/License-Apache_2.0-blue.svg new file mode 100644 index 0000000..ca466ca --- /dev/null +++ b/.github/License-Apache_2.0-blue.svg @@ -0,0 +1 @@ +License: Apache 2.0LicenseApache 2.0 \ No newline at end of file diff --git a/.github/slack.svg b/.github/slack.svg new file mode 100644 index 0000000..6cb641a --- /dev/null +++ b/.github/slack.svg @@ -0,0 +1,20 @@ + + slack + + + + + + + + + + + + + \ No newline at end of file diff --git a/README.md b/README.md index d99979a..9e475d0 100644 --- a/README.md +++ b/README.md @@ -1,19 +1,23 @@ -

Keploy x Python Sample Applications

+

Keploy Python Sample Applications

- - -

+ -This repo contains the samples for [Keploy's](https://keploy.io) Python-based Application. Please feel free to contribute if you'd like submit a sample for another use-case or library. + + ->**Note** :- Issue Creation is disabled on this Repository, please visit [here](https://github.com/keploy/keploy/issues/new/choose) to submit Issue. + + +

+This repo contains the samples for [Keploy's](https://keploy.io) integration with Python-based Application. Please feel free to contribute if you'd like submit a sample for another use-case or library. -## Sample Apps with Keploy +> **Note** :- Issue Creation is disabled on this Repository, please visit [here](https://github.com/keploy/keploy/issues/new/choose) to submit Issue. -1. [Flask-Mongo](https://github.com/keploy/samples-python/tree/main/flask-mongo) - This application is a simple student management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. +## Python Sample Apps with Keploy + +1. [Flask-Mongo](https://github.com/keploy/samples-python/tree/main/flask-mongo) - This application is a simple task management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. 2. [Django-Postgres](https://github.com/keploy/samples-python/tree/main/django-postgres) - This is an application to perform basic CRUD (Create, Read, Update, Delete) operations on user records built using Python's Django framework and PostgreSQL for data storage. @@ -23,12 +27,13 @@ This repo contains the samples for [Keploy's](https://keploy.io) Python-based Ap ## Community Support ❤️ -We'd love to collaborate with you to make Keploy great. To get started: -* [Slack](https://join.slack.com/t/keploy/shared_invite/zt-12rfbvc01-o54cOG0X1G6eVJTuI_orSA) - Discussions with the community and the team. -* [GitHub](https://github.com/keploy/keploy/issues) - For bug reports and feature requests. +### 🤔 Questions? + +Reach out to us. We're here to help! + +[![Slack](https://img.shields.io/badge/Slack-4A154B?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/keploy/shared_invite/zt-12rfbvc01-o54cOG0X1G6eVJTuI_orSA) +[![LinkedIn](https://img.shields.io/badge/linkedin-%230077B5.svg?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/keploy/) +[![YouTube](https://img.shields.io/badge/YouTube-%23FF0000.svg?style=for-the-badge&logo=YouTube&logoColor=white)](https://www.youtube.com/channel/UC6OTg7F4o0WkmNtSoob34lg) +[![Twitter](https://img.shields.io/badge/Twitter-%231DA1F2.svg?style=for-the-badge&logo=Twitter&logoColor=white)](https://twitter.com/Keployio) -[![Generic badge](https://img.shields.io/badge/Slack-teal.svg?style=for-the-badge)](https://join.slack.com/t/keploy/shared_invite/zt-12rfbvc01-o54cOG0X1G6eVJTuI_orSA) -[![Generic badge](https://img.shields.io/badge/LinkedIn-blue.svg?style=for-the-badge)](https://www.linkedin.com/company/keploy/) -[![Generic badge](https://img.shields.io/badge/Youtube-teal.svg?style=for-the-badge)](https://www.youtube.com/channel/UC6OTg7F4o0WkmNtSoob34lg) -[![Generic badge](https://img.shields.io/badge/Twitter-blue.svg?style=for-the-badge)](https://twitter.com/Keployio) -[![Generic badge](https://img.shields.io/badge/Documentation-teal.svg?style=for-the-badge)](https://keploy.io/docs/) +### 💖 Let's Build Together! From d3f81406001f44c6ab78d6cf5a001e3c2ede3054 Mon Sep 17 00:00:00 2001 From: Guruprasanna V Date: Fri, 26 Jul 2024 12:34:04 +0530 Subject: [PATCH 16/31] fix: fastapi with docker compose (#15) Signed-off-by: Guruprasanna02 --- fastapi-postgres/Dockerfile | 12 ++++++++---- fastapi-postgres/docker-compose.yml | 8 ++++++-- fastapi-postgres/entrypoint.sh | 10 ++++++++++ 3 files changed, 24 insertions(+), 6 deletions(-) create mode 100755 fastapi-postgres/entrypoint.sh diff --git a/fastapi-postgres/Dockerfile b/fastapi-postgres/Dockerfile index dc51d4b..85a9796 100644 --- a/fastapi-postgres/Dockerfile +++ b/fastapi-postgres/Dockerfile @@ -1,6 +1,13 @@ # Use the official Python image as the base image FROM python:3.11.5-bullseye +# Install PostgreSQL client +RUN apt-get update \ + && apt-get install -y --no-install-recommends \ + postgresql-client \ + curl \ + netcat-traditional + # Set the working directory to /app WORKDIR /app @@ -20,11 +27,8 @@ COPY . . # POSTGRES_HOST=0.0.0.0 \ # POSTGRES_PORT=5432 -# Install PostgreSQL client -RUN apt-get update && apt-get install -y postgresql-client - # Expose port 80 for the FastAPI application EXPOSE 8000 # Start the FastAPI application -CMD ["uvicorn", "application.main:app", "--host", "0.0.0.0", "--port", "8000"] +CMD [ "/app/entrypoint.sh" ] diff --git a/fastapi-postgres/docker-compose.yml b/fastapi-postgres/docker-compose.yml index 8ce911d..aa2e85c 100644 --- a/fastapi-postgres/docker-compose.yml +++ b/fastapi-postgres/docker-compose.yml @@ -13,7 +13,7 @@ services: - ./sql/init.sql:/docker-entrypoint-initdb.d/init.sql networks: - keploy-network - + app: container_name: fastapi-app image: fastapi @@ -26,4 +26,8 @@ services: depends_on: - postgres networks: - - keploy-network \ No newline at end of file + - keploy-network + +networks: + keploy-network: + external: true diff --git a/fastapi-postgres/entrypoint.sh b/fastapi-postgres/entrypoint.sh new file mode 100755 index 0000000..0c46028 --- /dev/null +++ b/fastapi-postgres/entrypoint.sh @@ -0,0 +1,10 @@ +#!/bin/sh + +until nc -z -v -w30 postgres 5432 +do + echo "Waiting for database connection..." + # wait for 5 seconds before check again + sleep 5 +done + +uvicorn application.main:app --host 0.0.0.0 --port 8000 From 9bdfbd8664ffa19d59a62c40c34d37f86b49457a Mon Sep 17 00:00:00 2001 From: Animesh Pathak <53110238+Sonichigo@users.noreply.github.com> Date: Sun, 4 Aug 2024 09:25:01 +0530 Subject: [PATCH 17/31] add coverage guide and refacator flask and fastapi apps (#25) * feat: add coverage in fastapi Signed-off-by: Animesh Pathak feat: add coverage in flask-mongo Signed-off-by: Animesh Pathak * feat: add coverage in flask-mongo Signed-off-by: Animesh Pathak * feat: add coverage in fastapi-twilio Signed-off-by: Animesh Pathak feat: add coverage in flask-mongo Signed-off-by: Animesh Pathak feat: add coverage in fastapi-postgres Signed-off-by: Animesh Pathak * Update README.md --------- Signed-off-by: Animesh Pathak --- fastapi-postgres/README.md | 20 +- fastapi-postgres/application/database.py | 2 +- fastapi-postgres/application/main.py | 25 +- fastapi-postgres/application/test_crud.py | 55 + fastapi-postgres/docker-compose.yml | 4 +- fastapi-postgres/img/testcases.png | Bin 0 -> 274773 bytes fastapi-postgres/img/testrun.png | Bin 0 -> 133392 bytes fastapi-postgres/keploy.yml | 43 + fastapi-postgres/keploy/test-set-1/mocks.yaml | 1219 ----------------- .../keploy/test-set-1/tests/test-1.yaml | 55 - .../keploy/test-set-1/tests/test-2.yaml | 55 - fastapi-postgres/requirements.txt | 1 - fastapi-twilio/README.md | 38 +- fastapi-twilio/img/testrun.png | Bin 0 -> 129893 bytes fastapi-twilio/keploy-config.yaml | 64 - fastapi-twilio/keploy.yml | 43 + fastapi-twilio/keploy/test-set-0/mocks.yaml | 162 --- .../keploy/test-set-0/tests/test-1.yaml | 58 - .../keploy/test-set-0/tests/test-2.yaml | 58 - .../keploy/test-set-0/tests/test-3.yaml | 58 - .../keploy/testReports/report-1.yaml | 284 ---- fastapi-twilio/main.py | 12 +- fastapi-twilio/requirements.txt | 25 + flask-mongo/.coverage | Bin 53248 -> 0 bytes flask-mongo/.coveragerc | 4 - flask-mongo/README.md | 271 +--- flask-mongo/__pycache__/app.cpython-310.pyc | Bin 2049 -> 0 bytes .../test_app.cpython-310-pytest-8.1.1.pyc | Bin 2471 -> 0 bytes .../__pycache__/test_app.cpython-310.pyc | Bin 2358 -> 0 bytes .../test_keploy.cpython-310-pytest-8.1.1.pyc | Bin 657 -> 0 bytes flask-mongo/app.py | 4 +- flask-mongo/call.sh | 13 + flask-mongo/docker-compose.yml | 6 +- flask-mongo/img/testcases.png | Bin 0 -> 226830 bytes flask-mongo/img/testrun-with-coverage.png | Bin 0 -> 160233 bytes flask-mongo/keploy.yml | 43 + .../reports/test-run-0/test-set-0-report.yaml | 446 ------ .../reports/test-run-1/test-set-0-report.yaml | 446 ------ flask-mongo/keploy/test-set-0/mocks.yaml | 319 ----- .../keploy/test-set-0/tests/test-1.yaml | 66 - .../keploy/test-set-0/tests/test-2.yaml | 56 - .../keploy/test-set-0/tests/test-3.yaml | 55 - .../keploy/test-set-0/tests/test-4.yaml | 51 - flask-mongo/requirements.txt | 40 +- 44 files changed, 366 insertions(+), 3735 deletions(-) create mode 100644 fastapi-postgres/application/test_crud.py create mode 100644 fastapi-postgres/img/testcases.png create mode 100644 fastapi-postgres/img/testrun.png create mode 100755 fastapi-postgres/keploy.yml delete mode 100755 fastapi-postgres/keploy/test-set-1/mocks.yaml delete mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-1.yaml delete mode 100755 fastapi-postgres/keploy/test-set-1/tests/test-2.yaml create mode 100644 fastapi-twilio/img/testrun.png delete mode 100755 fastapi-twilio/keploy-config.yaml create mode 100755 fastapi-twilio/keploy.yml delete mode 100755 fastapi-twilio/keploy/test-set-0/mocks.yaml delete mode 100755 fastapi-twilio/keploy/test-set-0/tests/test-1.yaml delete mode 100755 fastapi-twilio/keploy/test-set-0/tests/test-2.yaml delete mode 100755 fastapi-twilio/keploy/test-set-0/tests/test-3.yaml delete mode 100755 fastapi-twilio/keploy/testReports/report-1.yaml delete mode 100644 flask-mongo/.coverage delete mode 100644 flask-mongo/.coveragerc delete mode 100644 flask-mongo/__pycache__/app.cpython-310.pyc delete mode 100644 flask-mongo/__pycache__/test_app.cpython-310-pytest-8.1.1.pyc delete mode 100644 flask-mongo/__pycache__/test_app.cpython-310.pyc delete mode 100644 flask-mongo/__pycache__/test_keploy.cpython-310-pytest-8.1.1.pyc create mode 100644 flask-mongo/call.sh create mode 100644 flask-mongo/img/testcases.png create mode 100644 flask-mongo/img/testrun-with-coverage.png create mode 100755 flask-mongo/keploy.yml delete mode 100644 flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml delete mode 100644 flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml delete mode 100644 flask-mongo/keploy/test-set-0/mocks.yaml delete mode 100644 flask-mongo/keploy/test-set-0/tests/test-1.yaml delete mode 100644 flask-mongo/keploy/test-set-0/tests/test-2.yaml delete mode 100644 flask-mongo/keploy/test-set-0/tests/test-3.yaml delete mode 100644 flask-mongo/keploy/test-set-0/tests/test-4.yaml diff --git a/fastapi-postgres/README.md b/fastapi-postgres/README.md index d902662..ebe959d 100644 --- a/fastapi-postgres/README.md +++ b/fastapi-postgres/README.md @@ -13,6 +13,7 @@ Make the following requests to the respective endpoints - ```bash git clone https://github.com/keploy/samples-python.git && cd samples-python/fastapi-postgres +pip3 install coverage pip3 install -r requirements.txt ``` @@ -21,8 +22,7 @@ pip3 install -r requirements.txt Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release ```bash - curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh - keploy +curl -O -L https:///keploy.io/install.sh && source install.sh ``` ### Starting the PostgreSQL Instance @@ -34,9 +34,9 @@ docker-compose up -d ### Capture the Testcases -This command will start the recording of API calls using ebpf:- +This command will start the recording of API calls : -```shell +```sh sudo -E PATH=$PATH keploy record -c "uvicorn application.main:app --reload" ``` @@ -99,12 +99,20 @@ curl --location --request DELETE 'http://127.0.0.1:8000/students/1' Now all these API calls were captured as **editable** testcases and written to `keploy/tests` folder. The keploy directory would also have `mocks` file that contains all the outputs of postgres operations. +![keploy testcase](./img/testcases.png) + ## Run the Testcases Now let's run the application in test mode. ```shell -sudo -E PATH=$PATH keploy test -c "uvicorn application.main:app --reload" --delay 10 +sudo -E PATH=$PATH keploy test -c "python3 -m uvicorn application.main:app" --delay 10 ``` +We will get output something like below - + +![keploy testcase](./img/testrun.png) + +By making just 2 api call, we have generated a complete test suite for our application and acheived 72% coverage. + +So, no need to setup fake database/apis like Postgres or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Postgres 😄** -So, no need to setup fake database/apis like Postgres or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Postgres 😄** diff --git a/fastapi-postgres/application/database.py b/fastapi-postgres/application/database.py index 8b00777..17e68c4 100644 --- a/fastapi-postgres/application/database.py +++ b/fastapi-postgres/application/database.py @@ -3,7 +3,7 @@ from sqlalchemy.orm import sessionmaker -SQLALCHEMY_DATABASE_URL = "postgresql://postgres:postgres@postgres:5432/studentdb" +SQLALCHEMY_DATABASE_URL = "postgresql://postgres:postgres@localhost:5432/studentdb" engine = create_engine(SQLALCHEMY_DATABASE_URL) SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) diff --git a/fastapi-postgres/application/main.py b/fastapi-postgres/application/main.py index 294ad02..c078fe2 100644 --- a/fastapi-postgres/application/main.py +++ b/fastapi-postgres/application/main.py @@ -1,14 +1,21 @@ from fastapi import Depends, FastAPI, HTTPException from sqlalchemy.orm import Session +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker +from sqlalchemy.ext.declarative import declarative_base +import asyncio from . import models, crud, schemas -from .database import SessionLocal, engine +# Database setup +SQLALCHEMY_DATABASE_URL = "postgresql://postgres:postgres@localhost:5432/studentdb" +engine = create_engine(SQLALCHEMY_DATABASE_URL) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +Base = declarative_base() models.Base.metadata.create_all(bind=engine) app = FastAPI() - # Dependency def get_db(): db = SessionLocal() @@ -17,7 +24,6 @@ def get_db(): finally: db.close() - @app.post('/students/', response_model=schemas.Student) def create_student(student: schemas.StudentCreate, db: Session = Depends(get_db)): db_student = crud.get_student_byEmail(db, student_email=student.email) @@ -26,7 +32,6 @@ def create_student(student: schemas.StudentCreate, db: Session = Depends(get_db) data = crud.create_student(db, student=student) return data - @app.get('/students/', response_model=list[schemas.Student]) def read_students(skip: int = 0, limit: int = 100, db: Session = Depends(get_db)): students = crud.get_students(db, skip, limit) @@ -34,7 +39,6 @@ def read_students(skip: int = 0, limit: int = 100, db: Session = Depends(get_db) raise HTTPException(404, 'Data not found!!') return students - @app.get('/students/{student_id}', response_model=schemas.Student) def read_student(student_id: int, db: Session = Depends(get_db)): student = crud.get_student(db, student_id=student_id) @@ -42,7 +46,6 @@ def read_student(student_id: int, db: Session = Depends(get_db)): raise HTTPException(status_code=404, detail=f'Student with ID={student_id} not found!!') return student - @app.put('/students/{student_id}', response_model=schemas.Student) def update_student(student_id: int, student: schemas.StudentUpdate, db: Session = Depends(get_db)): student = crud.update_student(db, student=student, student_id=student_id) @@ -50,10 +53,18 @@ def update_student(student_id: int, student: schemas.StudentUpdate, db: Session raise HTTPException(status_code=404, detail=f'Student with ID={student_id} not found!!') return student - @app.delete('/students/{student_id}', response_model=schemas.Student) def delete_student(student_id: int, db: Session = Depends(get_db)): student = crud.delete_student(db, student_id=student_id) if student is None: raise HTTPException(status_code=404, detail=f'Student with ID={student_id} not found!!') return student + +# Graceful shutdown +@app.on_event("shutdown") +async def shutdown_event(): + # Example: Close the database connection pool + print("Shutting down...") + # Assuming SQLAlchemy engine has a dispose method to release resources + engine.dispose() + diff --git a/fastapi-postgres/application/test_crud.py b/fastapi-postgres/application/test_crud.py new file mode 100644 index 0000000..b33d4c8 --- /dev/null +++ b/fastapi-postgres/application/test_crud.py @@ -0,0 +1,55 @@ +import pytest +from sqlalchemy import create_engine +from sqlalchemy.orm import sessionmaker + +from .database import Base, SessionLocal +from . import crud, models, schemas + +# Create an in-memory SQLite database for testing +SQLALCHEMY_DATABASE_URL = "sqlite:///./test.db" +engine = create_engine(SQLALCHEMY_DATABASE_URL, connect_args={"check_same_thread": False}) +TestingSessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) + +# Create the database tables +Base.metadata.create_all(bind=engine) + +@pytest.fixture(scope="module") +def db_session(): + connection = engine.connect() + transaction = connection.begin() + session = TestingSessionLocal(bind=connection) + + yield session + + session.close() + transaction.rollback() + connection.close() + +def test_create_student(db_session): + student_in = schemas.StudentCreate(name="John Doe", email="john.doe@example.com", password="password", stream="Science") + student = crud.create_student(db_session, student_in) + assert student.name == "John Doe" + assert student.email == "john.doe@example.com" + +def test_get_student(db_session): + student_in = schemas.StudentCreate(name="Jane Doe", email="jane.doe@example.com", password="password", stream="Arts") + student = crud.create_student(db_session, student_in) + fetched_student = crud.get_student(db_session, student.id) + assert fetched_student.name == "Jane Doe" + assert fetched_student.email == "jane.doe@example.com" + +def test_update_student(db_session): + student_in = schemas.StudentCreate(name="Jim Beam", email="jim.beam@example.com", password="password", stream="Commerce") + student = crud.create_student(db_session, student_in) + student_update = schemas.StudentUpdate(name="Jim Updated", email="jim.updated@example.com", password="newpassword", stream="Commerce") + updated_student = crud.update_student(db_session, student_update, student.id) + assert updated_student.name == "Jim Updated" + assert updated_student.email == "jim.updated@example.com" + +def test_delete_student(db_session): + student_in = schemas.StudentCreate(name="Will Smith", email="will.smith@example.com", password="password", stream="Engineering") + student = crud.create_student(db_session, student_in) + deleted_student = crud.delete_student(db_session, student.id) + assert deleted_student is not None + assert deleted_student.name == "Will Smith" + assert crud.get_student(db_session, student.id) is None diff --git a/fastapi-postgres/docker-compose.yml b/fastapi-postgres/docker-compose.yml index aa2e85c..80ec447 100644 --- a/fastapi-postgres/docker-compose.yml +++ b/fastapi-postgres/docker-compose.yml @@ -1,4 +1,4 @@ -version: '3' +version: '3.9' services: postgres: @@ -30,4 +30,4 @@ services: networks: keploy-network: - external: true + external: true \ No newline at end of file diff --git a/fastapi-postgres/img/testcases.png b/fastapi-postgres/img/testcases.png new file mode 100644 index 0000000000000000000000000000000000000000..1c4a2f059b07558a52f13e625ae2e4c1de124d2e GIT binary patch literal 274773 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%0D#a*nLe=(WS>9h8|}A%D5oxh+md7tp^IM<_~+3& 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 aX!ep3{%otu-VwF(uxi2ng@TzY8$ literal 0 HcmV?d00001 diff --git a/fastapi-postgres/img/testrun.png b/fastapi-postgres/img/testrun.png new file mode 100644 index 0000000000000000000000000000000000000000..11029fc2c7ad771b1fd0c5c0fff5433f9906471a GIT binary patch literal 133392 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⁢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%0AlX?`>PP2H$8p7cinqOPjVTM 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 Ys|L$+M`F_QiGYWun%=!~73;A70ubbO3;+NC literal 0 HcmV?d00001 diff --git a/fastapi-postgres/keploy.yml b/fastapi-postgres/keploy.yml new file mode 100755 index 0000000..d6e6628 --- /dev/null +++ b/fastapi-postgres/keploy.yml @@ -0,0 +1,43 @@ +path: "" +appId: 0 +appName: "" +command: uvicorn application.main:app --reload +port: 0 +dnsPort: 26789 +proxyPort: 16789 +debug: false +disableTele: false +disableANSI: false +containerName: "" +networkName: "" +buildDelay: 30 +test: + selectedTests: {} + globalNoise: + global: {} + test-sets: {} + delay: 5 + apiTimeout: 5 + skipCoverage: false + coverageReportPath: "" + ignoreOrdering: true + mongoPassword: default@123 + language: "" + removeUnusedMocks: false + fallBackOnMiss: false + jacocoAgentPath: "" + basePath: "" + mocking: true + ignoredTests: {} +record: + filters: [] + recordTimer: 0s +configPath: "" +bypassRules: [] +generateGithubActions: true +keployContainer: keploy-v2 +keployNetwork: keploy-network +cmdType: native +inCi: false + +# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file. diff --git a/fastapi-postgres/keploy/test-set-1/mocks.yaml b/fastapi-postgres/keploy/test-set-1/mocks.yaml deleted file mode 100755 index 86b47c1..0000000 --- a/fastapi-postgres/keploy/test-set-1/mocks.yaml +++ /dev/null @@ -1,1219 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-0 -spec: - metadata: - type: config - postgresrequests: - - identifier: StartupRequest - length: 8 - payload: AAAACATSFi8= - ssl_request: - is_ssl: true - auth_type: 0 - postgresresponses: - - payload: Tg== - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.216898875Z - restimestampmock: 2024-02-09T10:20:50.218562705Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-1 -spec: - metadata: - type: config - postgresrequests: - - identifier: StartupRequest - payload: AAAAKgADAAB1c2VyAHBvc3RncmVzAGRhdGFiYXNlAHN0dWRlbnRkYgAA - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl: - auth_mechanisms: - - SCRAM-SHA-256 - msg_type: 82 - auth_type: 10 - reqtimestampmock: 2024-02-09T10:20:50.232737784Z - restimestampmock: 2024-02-09T10:20:50.233296602Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-2 -spec: - metadata: - type: config - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - password_message: - password: SCRAM-SHA-256 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_continue: {data: [114, 61, 68, 54, 118, 109, 56, 118, 117, 82, 116, 89, 111, 116, 75, 81, 75, 86, 74, 100, 55, 47, 85, 115, 107, 90, 70, 78, 88, 79, 112, 80, 88, 84, 67, 105, 103, 86, 51, 101, 73, 90, 48, 105, 119, 117, 65, 106, 111, 83, 44, 115, 61, 117, 110, 74, 50, 122, 68, 57, 75, 121, 76, 47, 109, 83, 114, 117, 111, 102, 121, 55, 112, 84, 81, 61, 61, 44, 105, 61, 52, 48, 57, 54]} - msg_type: 82 - auth_type: 11 - reqtimestampmock: 2024-02-09T10:20:50.234459113Z - restimestampmock: 2024-02-09T10:20:50.234488904Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-3 -spec: - metadata: - type: config - postgresrequests: - - header: [p] - identifier: ClientRequest - length: 8 - msg_type: 112 - auth_type: 0 - postgresresponses: - - header: [R, R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - authentication_sasl_final: {data: [118, 61, 118, 48, 53, 82, 117, 66, 89, 50, 52, 51, 72, 85, 67, 97, 116, 102, 83, 55, 67, 69, 70, 43, 72, 84, 106, 89, 90, 79, 118, 115, 115, 78, 48, 56, 116, 120, 99, 48, 103, 106, 105, 119, 85, 61]} - backend_key_data: - process_id: 34 - secret_key: 4065475156 - parameter_status: - - name: in_hot_standby - value: "off" - - name: integer_datetimes - value: "on" - - name: TimeZone - value: Etc/UTC - - name: IntervalStyle - value: postgres - - name: is_superuser - value: "on" - - name: application_name - value: "" - - name: default_transaction_read_only - value: "off" - - name: scram_iterations - value: "4096" - - name: DateStyle - value: ISO, MDY - - name: standard_conforming_strings - value: "on" - - name: session_authorization - value: postgres - - name: client_encoding - value: UTF8 - - name: server_version - value: 16.1 (Debian 16.1-1.pgdg120+1) - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - - name: server_encoding - value: UTF8 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.240419203Z - restimestampmock: 2024-02-09T10:20:50.24047866Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-4 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.241574547Z - restimestampmock: 2024-02-09T10:20:50.241651254Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-5 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAHdTRUxFQ1QgdC5vaWQsIHR5cGFycmF5CkZST00gcGdfdHlwZSB0IEpPSU4gcGdfbmFtZXNwYWNlIG5zCiAgICBPTiB0eXBuYW1lc3BhY2UgPSBucy5vaWQKV0hFUkUgdHlwbmFtZSA9ICdoc3RvcmUnOwoA - query: - string: 'SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid WHERE typname = ''hstore''; ' - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [111, 105, 100], table_oid: 1247, table_attribute_number: 1, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}, {name: [116, 121, 112, 97, 114, 114, 97, 121], table_oid: 1247, table_attribute_number: 15, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.243360791Z - restimestampmock: 2024-02-09T10:20:50.243385416Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-6 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.244072772Z - restimestampmock: 2024-02-09T10:20:50.244098563Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-7 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.244693006Z - restimestampmock: 2024-02-09T10:20:50.244715338Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-8 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: select pg_catalog.version() - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAACAAAXZlcnNpb24AAAAAAAAAAAAAGf///////wAARAAAAIMAAQAAAHlQb3N0Z3JlU1FMIDE2LjEgKERlYmlhbiAxNi4xLTEucGdkZzEyMCsxKSBvbiBhYXJjaDY0LXVua25vd24tbGludXgtZ251LCBjb21waWxlZCBieSBnY2MgKERlYmlhbiAxMi4yLjAtMTQpIDEyLjIuMCwgNjQtYml0QwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}, {row_values: ['PostgreSQL 16.1 (Debian 16.1-1.pgdg120+1) on aarch64-unknown-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [118, 101, 114, 115, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.24516216Z - restimestampmock: 2024-02-09T10:20:50.245191367Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-9 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: select current_schema() - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAACcAAWN1cnJlbnRfc2NoZW1hAAAAAAAAAAAAABMAQP////8AAEQAAAAQAAEAAAAGcHVibGljQwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: [public]}, {row_values: [public]}, {row_values: [public]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [99, 117, 114, 114, 101, 110, 116, 95, 115, 99, 104, 101, 109, 97], table_oid: 0, table_attribute_number: 0, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.246241214Z - restimestampmock: 2024-02-09T10:20:50.246281713Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-10 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: show transaction isolation level - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAAC4AAXRyYW5zYWN0aW9uX2lzb2xhdGlvbgAAAAAAAAAAAAAZ////////AABEAAAAGAABAAAADnJlYWQgY29tbWl0dGVkQwAAAAlTSE9XAFoAAAAFVA== - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 72 - - 79 - - 87 - data_row: [{row_values: [read committed]}, {row_values: [read committed]}, {row_values: [read committed]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [116, 114, 97, 110, 115, 97, 99, 116, 105, 111, 110, 95, 105, 115, 111, 108, 97, 116, 105, 111, 110], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.247356559Z - restimestampmock: 2024-02-09T10:20:50.247387933Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-11 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: show standard_conforming_strings - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAADQAAXN0YW5kYXJkX2NvbmZvcm1pbmdfc3RyaW5ncwAAAAAAAAAAAAAZ////////AABEAAAADAABAAAAAm9uQwAAAAlTSE9XAFoAAAAFVA== - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 72 - - 79 - - 87 - data_row: [{row_values: ["on"]}, {row_values: ["on"]}, {row_values: ["on"]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 97, 110, 100, 97, 114, 100, 95, 99, 111, 110, 102, 111, 114, 109, 105, 110, 103, 95, 115, 116, 114, 105, 110, 103, 115], table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.248114456Z - restimestampmock: 2024-02-09T10:20:50.24815283Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-12 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.248975766Z - restimestampmock: 2024-02-09T10:20:50.24899789Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-13 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.252045225Z - restimestampmock: 2024-02-09T10:20:50.252072266Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-14 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAYdTRUxFQ1QgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lIApGUk9NIHBnX2NhdGFsb2cucGdfY2xhc3MgSk9JTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZSBPTiBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5vaWQgPSBwZ19jYXRhbG9nLnBnX2NsYXNzLnJlbG5hbWVzcGFjZSAKV0hFUkUgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxuYW1lID0gJ3N0dWRlbnRzJyBBTkQgcGdfY2F0YWxvZy5wZ19jbGFzcy5yZWxraW5kID0gQU5ZIChBUlJBWVsncicsICdwJywgJ2YnLCAndicsICdtJ10pIEFORCBwZ19jYXRhbG9nLnBnX3RhYmxlX2lzX3Zpc2libGUocGdfY2F0YWxvZy5wZ19jbGFzcy5vaWQpIEFORCBwZ19jYXRhbG9nLnBnX25hbWVzcGFjZS5uc3BuYW1lICE9ICdwZ19jYXRhbG9nJwA= - query: - string: SELECT pg_catalog.pg_class.relname FROM pg_catalog.pg_class JOIN pg_catalog.pg_namespace ON pg_catalog.pg_namespace.oid = pg_catalog.pg_class.relnamespace WHERE pg_catalog.pg_class.relname = 'students' AND pg_catalog.pg_class.relkind = ANY (ARRAY['r', 'p', 'f', 'v', 'm']) AND pg_catalog.pg_table_is_visible(pg_catalog.pg_class.oid) AND pg_catalog.pg_namespace.nspname != 'pg_catalog' - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAACAAAXJlbG5hbWUAAAAE6wACAAAAEwBA/////wAARAAAABIAAQAAAAhzdHVkZW50c0MAAAANU0VMRUNUIDEAWgAAAAVU - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: [students]}, {row_values: [students]}, {row_values: [students]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [114, 101, 108, 110, 97, 109, 101], table_oid: 1259, table_attribute_number: 2, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.253162445Z - restimestampmock: 2024-02-09T10:20:50.253222319Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-15 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:20:50.254107087Z - restimestampmock: 2024-02-09T10:20:50.25412767Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-16 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.542685552Z - restimestampmock: 2024-02-09T10:21:01.542714843Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-17 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAATBTRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnZXZhd2hpdGVAZXhhbXBsZS5jb20nIAogTElNSVQgMQA= - query: - string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'evawhite@example.com' LIMIT 1 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.543969268Z - restimestampmock: 2024-02-09T10:21:01.544053057Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-18 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('Eva White', 'evawhite@example.com', 'sfwbxijuf222', 'Mathematics') RETURNING students."ID" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMUMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 73 - - 78 - - 83 - - 69 - - 82 - - 84 - - 32 - - 48 - - 32 - - 49 - data_row: [{row_values: ["1"]}, {row_values: ["1"]}, {row_values: ["1"]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.546426702Z - restimestampmock: 2024-02-09T10:21:01.546463701Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-19 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.551006372Z - restimestampmock: 2024-02-09T10:21:01.55108062Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-20 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.552699118Z - restimestampmock: 2024-02-09T10:21:01.552721743Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-21 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDEA - query: - string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 1 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABPAAUAAAABMQAAAAlFdmEgV2hpdGUAAAAUZXZhd2hpdGVAZXhhbXBsZS5jb20AAAAMc2Z3YnhpanVmMjIyAAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}, {row_values: ["1", Eva White, evawhite@example.com, sfwbxijuf222, Mathematics]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.553203147Z - restimestampmock: 2024-02-09T10:21:01.553236062Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-22 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:01.556089153Z - restimestampmock: 2024-02-09T10:21:01.556110861Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-23 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.223148624Z - restimestampmock: 2024-02-09T10:21:11.223211164Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-24 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAS9TRUxFQ1Qgc3R1ZGVudHMuIklEIiBBUyAic3R1ZGVudHNfSUQiLCBzdHVkZW50cy4iTmFtZSIgQVMgInN0dWRlbnRzX05hbWUiLCBzdHVkZW50cy4iRW1haWwiIEFTICJzdHVkZW50c19FbWFpbCIsIHN0dWRlbnRzLiJIYXNoZWQgUGFzc3dvcmQiIEFTICJzdHVkZW50c19IYXNoZWQgUGFzc3dvcmQiLCBzdHVkZW50cy4iU3ViamVjdCBTdHJlYW0iIEFTICJzdHVkZW50c19TdWJqZWN0IFN0cmVhbSIgCkZST00gc3R1ZGVudHMgCldIRVJFIHN0dWRlbnRzLiJFbWFpbCIgPSAnam9obmRvZUBleGFtcGxlLmNvbScgCiBMSU1JVCAxAA== - query: - string: SELECT students."ID" AS "students_ID", students."Name" AS "students_Name", students."Email" AS "students_Email", students."Hashed Password" AS "students_Hashed Password", students."Subject Stream" AS "students_Subject Stream" FROM students WHERE students."Email" = 'johndoe@example.com' LIMIT 1 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 48 - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [115, 116, 117, 100, 101, 110, 116, 115, 95, 83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.224563961Z - restimestampmock: 2024-02-09T10:21:11.224606043Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-25 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: INSERT INTO students ("Name", "Email", "Hashed Password", "Subject Stream") VALUES ('John Doe', 'johndoe@example.com', 'skpioepf234', 'Mathematics') RETURNING students."ID" - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAABsAAUlEAAAAYAEAAQAAABcABP////8AAEQAAAALAAEAAAABMkMAAAAPSU5TRVJUIDAgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 73 - - 78 - - 83 - - 69 - - 82 - - 84 - - 32 - - 48 - - 32 - - 49 - data_row: [{row_values: ["2"]}, {row_values: ["2"]}, {row_values: ["2"]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.226669655Z - restimestampmock: 2024-02-09T10:21:11.226748861Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-26 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: COMMIT - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 67 - - 79 - - 77 - - 77 - - 73 - - 84 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.232155218Z - restimestampmock: 2024-02-09T10:21:11.232190134Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-27 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: BEGIN - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 66 - - 69 - - 71 - - 73 - - 78 - ready_for_query: - txstatus: 84 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.233212565Z - restimestampmock: 2024-02-09T10:21:11.233238147Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-28 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - payload: UQAAAJtTRUxFQ1Qgc3R1ZGVudHMuIklEIiwgc3R1ZGVudHMuIk5hbWUiLCBzdHVkZW50cy4iRW1haWwiLCBzdHVkZW50cy4iSGFzaGVkIFBhc3N3b3JkIiwgc3R1ZGVudHMuIlN1YmplY3QgU3RyZWFtIiAKRlJPTSBzdHVkZW50cyAKV0hFUkUgc3R1ZGVudHMuIklEIiA9IDIA - query: - string: SELECT students."ID", students."Name", students."Email", students."Hashed Password", students."Subject Stream" FROM students WHERE students."ID" = 2 - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [T, D, C, Z] - identifier: ServerResponse - length: 8 - payload: VAAAAI0ABUlEAAAAYAEAAQAAABcABP////8AAE5hbWUAAABgAQACAAAEE////////wAARW1haWwAAABgAQADAAAEE////////wAASGFzaGVkIFBhc3N3b3JkAAAAYAEABAAABBP///////8AAFN1YmplY3QgU3RyZWFtAAAAYAEABQAABBP///////8AAEQAAABMAAUAAAABMgAAAAhKb2huIERvZQAAABNqb2huZG9lQGV4YW1wbGUuY29tAAAAC3NrcGlvZXBmMjM0AAAAC01hdGhlbWF0aWNzQwAAAA1TRUxFQ1QgMQBaAAAABVQ= - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 83 - - 69 - - 76 - - 69 - - 67 - - 84 - - 32 - - 49 - data_row: [{row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}, {row_values: ["2", John Doe, johndoe@example.com, skpioepf234, Mathematics]}] - ready_for_query: - txstatus: 84 - row_description: {fields: [{name: [73, 68], table_oid: 24577, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {name: [78, 97, 109, 101], table_oid: 24577, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [69, 109, 97, 105, 108], table_oid: 24577, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [72, 97, 115, 104, 101, 100, 32, 80, 97, 115, 115, 119, 111, 114, 100], table_oid: 24577, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}, {name: [83, 117, 98, 106, 101, 99, 116, 32, 83, 116, 114, 101, 97, 109], table_oid: 24577, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: -1, format: 0}]} - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.233889547Z - restimestampmock: 2024-02-09T10:21:11.233922754Z ---- -version: api.keploy.io/v1beta1 -kind: Postgres -name: mock-29 -spec: - metadata: - type: config - postgresrequests: - - header: [Q] - identifier: ClientRequest - length: 8 - query: - string: ROLLBACK - msg_type: 81 - auth_type: 0 - postgresresponses: - - header: [C, Z] - identifier: ServerResponse - length: 8 - authentication_md5_password: - salt: - - 0 - - 0 - - 0 - - 0 - command_complete: - - command_tag: - - 82 - - 79 - - 76 - - 76 - - 66 - - 65 - - 67 - - 75 - ready_for_query: - txstatus: 73 - msg_type: 90 - auth_type: 0 - reqtimestampmock: 2024-02-09T10:21:11.236845177Z - restimestampmock: 2024-02-09T10:21:11.236868259Z diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml deleted file mode 100755 index e5100d2..0000000 --- a/fastapi-postgres/keploy/test-set-1/tests/test-1.yaml +++ /dev/null @@ -1,55 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-1 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Content-Length: "105" - Content-Type: application/json - Host: 127.0.0.1:8000 - User-Agent: curl/8.2.1 - body: |- - { - "name": "Eva White", - "email": "evawhite@example.com", - "password": "evawhite111" - } - body_type: "" - timestamp: 2024-02-09T10:21:01.532943145Z - host: "" - resp: - status_code: 200 - header: - Content-Length: "107" - Content-Type: application/json - Date: Fri, 09 Feb 2024 10:21:00 GMT - Server: uvicorn - body: '{"name":"Eva White","email":"evawhite@example.com","password":"sfwbxijuf222","stream":"Mathematics","id":1}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2024-02-09T10:21:03.574647019Z - objects: [] - assertions: - noise: - header.Date: [] - created: 1707474063 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/students/ \ - --header 'Host: 127.0.0.1:8000' \ - --header 'User-Agent: curl/8.2.1' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --data '{ - "name": "Eva White", - "email": "evawhite@example.com", - "password": "evawhite111" - }' diff --git a/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml b/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml deleted file mode 100755 index ecddaf6..0000000 --- a/fastapi-postgres/keploy/test-set-1/tests/test-2.yaml +++ /dev/null @@ -1,55 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-2 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/students/ - header: - Accept: '*/*' - Content-Length: "106" - Content-Type: application/json - Host: 127.0.0.1:8000 - User-Agent: curl/8.2.1 - body: |4- - { - "name": "John Doe", - "email": "johndoe@example.com", - "password": "johndoe123" - } - body_type: "" - timestamp: 2024-02-09T10:21:11.21894436Z - host: "" - resp: - status_code: 200 - header: - Content-Length: "104" - Content-Type: application/json - Date: Fri, 09 Feb 2024 10:21:10 GMT - Server: uvicorn - body: '{"name":"John Doe","email":"johndoe@example.com","password":"skpioepf234","stream":"Mathematics","id":2}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2024-02-09T10:21:13.238027535Z - objects: [] - assertions: - noise: - header.Date: [] - created: 1707474073 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/students/ \ - --header 'User-Agent: curl/8.2.1' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --header 'Host: 127.0.0.1:8000' \ - --data ' { - "name": "John Doe", - "email": "johndoe@example.com", - "password": "johndoe123" - }' diff --git a/fastapi-postgres/requirements.txt b/fastapi-postgres/requirements.txt index 5201c90..c7ad5e0 100644 --- a/fastapi-postgres/requirements.txt +++ b/fastapi-postgres/requirements.txt @@ -16,7 +16,6 @@ itsdangerous==2.1.2 Jinja2==3.1.2 MarkupSafe==2.1.3 orjson==3.9.8 -psycopg2==2.9.9 psycopg2-binary==2.9.9 pydantic==2.4.2 pydantic-extra-types==2.1.0 diff --git a/fastapi-twilio/README.md b/fastapi-twilio/README.md index 0afbc7e..d1d5ca9 100644 --- a/fastapi-twilio/README.md +++ b/fastapi-twilio/README.md @@ -6,6 +6,7 @@ A sample FastAPI-Twilio app to test Keploy integration capabilities using [FastA ```bash git clone https://github.com/keploy/samples-python.git && cd samples-python/fastapi-twilio +pip3 install coverage pip3 install -r requirements.txt ``` @@ -14,8 +15,7 @@ pip3 install -r requirements.txt Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release ```bash - curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh - keploy +curl -O https://keploy.io/install.sh && source install.sh ``` ### Get your Twilio Credentials @@ -28,7 +28,7 @@ Once you get the Twilio Account SID, Auth Token, and Phone Number, modify the `. This command will start the recording of API calls:- ```shell -keploy record -c "uvicorn main:app --reload" +keploy record -c "uvicorn main:app" ``` Make API Calls using Hoppscotch, Postman or cURL command. Keploy with capture those calls to generate the test-suites containing testcases and data mocks. @@ -37,25 +37,25 @@ Make API Calls using Hoppscotch, Postman or cURL command. Keploy with capture th 1. Replace the place holder below i.e. `YOUR_REGISTERED_PERSONAL_PHONE_NUMBER` with your registered personal phone number that you linked with Twilio. - ```bash - curl --location 'http://127.0.0.1:8000/send-sms/' \ - --header 'Content-Type: application/json' \ - --data '{ - "Body": "Test, testtt, testttttttssss :)", - "To": "YOUR_REGISTERED_PERSONAL_PHONE_NUMBER", - }' - ``` +```bash +curl --location 'http://127.0.0.1:8000/send-sms/' \ + --header 'Content-Type: application/json' \ + --data-raw '{ + "Body": "Test", + "To": "" + }' +``` 2. Replace the place holder below i.e. `SOME_WRONG_PHONE_NUMBER` with any wrong phone number and make the request. - ```bash - curl --location 'http://127.0.0.1:8000/send-sms/' \ +```bash +curl --location 'http://127.0.0.1:8000/send-sms/' \ --header 'Content-Type: application/json' \ - --data '{ + --data-raw '{ "Body": "Test, testtt, testttttttssss :)", - "To": "SOME_WRONG_PHONE_NUMBER", + "To": "", }' - ``` +``` Now all these API calls were captured as **editable** testcases and written to `keploy/tests` folder. The keploy directory would also have `mocks` file that contains all the outputs of Twilio operations. @@ -64,7 +64,9 @@ Now all these API calls were captured as **editable** testcases and written to ` Now let's run the application in test mode. ```shell -keploy test -c "uvicorn main:app --reload" --delay 10 +keploy test -c "python3 -m uvicorn main:app" --delay 10 ``` -So, no need to setup fake apis like Twilio or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Twilio 😄** +So, no need to setup fake apis like Twilio or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Twilio 😄** . We can notice that for a single API without using Twilio, we got around 89% of coverage : + +![testRun](./img/testrun.png) diff --git a/fastapi-twilio/img/testrun.png b/fastapi-twilio/img/testrun.png new file mode 100644 index 0000000000000000000000000000000000000000..8173f8e977bda27ab645e0e32ec02e4a6b3c48eb GIT binary patch literal 129893 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

>|DwLd>&-_ZFh)Yx) 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

0e}F41{{*hYT?IJR`yG<8u@U2{ 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 z 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 literal 0 HcmV?d00001 diff --git a/fastapi-twilio/keploy-config.yaml b/fastapi-twilio/keploy-config.yaml deleted file mode 100755 index c7e3e02..0000000 --- a/fastapi-twilio/keploy-config.yaml +++ /dev/null @@ -1,64 +0,0 @@ -record: - path: "" - # mandatory - command: "" - proxyport: 0 - containerName: "" - networkName: "" - delay: 5 - passThroughPorts: [] -test: - path: "" - # mandatory - command: "" - proxyport: 0 - containerName: "" - networkName: "" - testSets: [] - globalNoise: |- - { - "global": { - "body": {}, - "header": {} - }, - "test-sets": { - "test-set-name": { - "body": {}, - "header": {} - } - } - } - delay: 5 - apiTimeout: 5 - passThroughPorts: [] - # - # Example on using globalNoise - # globalNoise: |- - # { - # "global": { - # "body": { - # # to ignore some values for a field, - # # pass regex patterns to the corresponding array value - # "url": ["https?://\S+", "http://\S+"], - # }, - # "header": { - # # to ignore the entire field, pass an empty array - # "Date: [], - # } - # }, - # # to ignore fields or the corresponding values for a specific test-set, - # # pass the test-set-name as a key to the "test-sets" object and - # # populate the corresponding "body" and "header" objects - # "test-sets": { - # "test-set-1": { - # "body": { - # # ignore all the values for the "url" field - # "url": [] - # }, - # "header": { - # # we can also pass the exact value to ignore for a field - # "User-Agent": ["PostmanRuntime/7.34.0"] - # } - # } - # } - # } diff --git a/fastapi-twilio/keploy.yml b/fastapi-twilio/keploy.yml new file mode 100755 index 0000000..34deba8 --- /dev/null +++ b/fastapi-twilio/keploy.yml @@ -0,0 +1,43 @@ +path: "" +appId: 0 +appName: "" +command: uvicorn main:app +port: 0 +dnsPort: 26789 +proxyPort: 16789 +debug: false +disableTele: false +disableANSI: false +containerName: "" +networkName: "" +buildDelay: 30 +test: + selectedTests: {} + globalNoise: + global: {} + test-sets: {} + delay: 5 + apiTimeout: 5 + skipCoverage: false + coverageReportPath: "" + ignoreOrdering: true + mongoPassword: default@123 + language: "" + removeUnusedMocks: false + fallBackOnMiss: false + jacocoAgentPath: "" + basePath: "" + mocking: true + ignoredTests: {} +record: + filters: [] + recordTimer: 0s +configPath: "" +bypassRules: [] +generateGithubActions: true +keployContainer: keploy-v2 +keployNetwork: keploy-network +cmdType: native +inCi: false + +# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file. diff --git a/fastapi-twilio/keploy/test-set-0/mocks.yaml b/fastapi-twilio/keploy/test-set-0/mocks.yaml deleted file mode 100755 index cd2a8bf..0000000 --- a/fastapi-twilio/keploy/test-set-0/mocks.yaml +++ /dev/null @@ -1,162 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: mocks -spec: - metadata: - name: Http - operation: POST - type: HTTP_CLIENT - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: /2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages.json - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate - Authorization: Basic QUMxOTQxMzY4N2Q5Y2UyOGM4MGNkYTk0NDczMGY4YjI4NjpjMTc0MDc5YzU2NTA0N2FmYWJmNDk5MWI2ZGQ1MmFiYg== - Connection: keep-alive - Content-Length: "82" - Content-Type: application/x-www-form-urlencoded - User-Agent: python-requests/2.31.0 - body: Body=Test%2C+testtt%2C+testttttttssss+%3A%29&From=%2B16413324066&To=%2B91700004379 - body_type: "" - timestamp: 0001-01-01T00:00:00Z - resp: - status_code: 400 - header: - Access-Control-Allow-Credentials: "true" - Access-Control-Allow-Headers: Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Idempotency-Key - Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS - Access-Control-Allow-Origin: '*' - Access-Control-Expose-Headers: ETag - Connection: keep-alive - Content-Length: 158,158 - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:26:29 GMT - Strict-Transport-Security: max-age=31536000 - Twilio-Concurrent-Requests: "1" - Twilio-Request-Duration: "0.051" - Twilio-Request-Id: RQec3c4676524fe2951583489e90bc1b33 - X-Api-Domain: api.twilio.com - X-Home-Region: us1 - X-Powered-By: AT-5000 - X-Shenanigans: none - body: '{"code": 21211, "message": "The ''To'' number +9170000XXXX is not a valid phone number", "more_info": "https://www.twilio.com/docs/errors/21211", "status": 400}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 0001-01-01T00:00:00Z - objects: [] - created: 1699953989 - reqTimestampMock: 2023-11-14T14:56:28.791864295+05:30 - resTimestampMock: 2023-11-14T14:56:29.304057844+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Http -name: mocks -spec: - metadata: - name: Http - operation: POST - type: HTTP_CLIENT - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: /2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages.json - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate - Authorization: Basic QUMxOTQxMzY4N2Q5Y2UyOGM4MGNkYTk0NDczMGY4YjI4NjpjMTc0MDc5YzU2NTA0N2FmYWJmNDk5MWI2ZGQ1MmFiYg== - Connection: keep-alive - Content-Length: "83" - Content-Type: application/x-www-form-urlencoded - User-Agent: python-requests/2.31.0 - body: Body=Test%2C+testtt%2C+testttttttssss+%3A%29&From=%2B16413324066&To=%2B917000043797 - body_type: "" - timestamp: 0001-01-01T00:00:00Z - resp: - status_code: 201 - header: - Access-Control-Allow-Credentials: "true" - Access-Control-Allow-Headers: Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Idempotency-Key - Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS - Access-Control-Allow-Origin: '*' - Access-Control-Expose-Headers: ETag - Connection: keep-alive - Content-Length: 834,834 - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:26:35 GMT - Twilio-Concurrent-Requests: "1" - Twilio-Request-Duration: "0.131" - Twilio-Request-Id: RQ2f5288499581f3fe12524b11bbb3d866 - X-Api-Domain: api.twilio.com - X-Home-Region: us1 - X-Powered-By: AT-5000 - X-Shenanigans: none - body: '{"body": "Sent from your Twilio trial account - Test, testtt, testttttttssss :)", "num_segments": "1", "direction": "outbound-api", "from": "+16413324066", "date_updated": "Tue, 14 Nov 2023 09:26:35 +0000", "price": null, "error_message": null, "uri": "/2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages/SM2f5288499581f3fe12524b11bbb3d866.json", "account_sid": "AC19413687d9ce28c80cda944730f8b286", "num_media": "0", "to": "+917000043797", "date_created": "Tue, 14 Nov 2023 09:26:35 +0000", "status": "queued", "sid": "SM2f5288499581f3fe12524b11bbb3d866", "date_sent": null, "messaging_service_sid": null, "error_code": null, "price_unit": "USD", "api_version": "2010-04-01", "subresource_uris": {"media": "/2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages/SM2f5288499581f3fe12524b11bbb3d866/Media.json"}}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 0001-01-01T00:00:00Z - objects: [] - created: 1699953995 - reqTimestampMock: 2023-11-14T14:56:34.833506359+05:30 - resTimestampMock: 2023-11-14T14:56:35.27188354+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Http -name: mocks -spec: - metadata: - name: Http - operation: POST - type: HTTP_CLIENT - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: /2010-04-01/Accounts/AC19413687d9ce28c80cda944730f8b286/Messages.json - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate - Authorization: Basic QUMxOTQxMzY4N2Q5Y2UyOGM4MGNkYTk0NDczMGY4YjI4NjpjMTc0MDc5YzU2NTA0N2FmYWJmNDk5MWI2ZGQ1MmFiYg== - Connection: keep-alive - Content-Length: "81" - Content-Type: application/x-www-form-urlencoded - User-Agent: python-requests/2.31.0 - body: Body=Test%2C+testtt%2C+testttttttssss+%3A%29&From=%2B16413324066&To=%2B9170000437 - body_type: "" - timestamp: 0001-01-01T00:00:00Z - resp: - status_code: 400 - header: - Access-Control-Allow-Credentials: "true" - Access-Control-Allow-Headers: Accept, Authorization, Content-Type, If-Match, If-Modified-Since, If-None-Match, If-Unmodified-Since, Idempotency-Key - Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS - Access-Control-Allow-Origin: '*' - Access-Control-Expose-Headers: ETag - Connection: keep-alive - Content-Length: 335,335 - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:27:21 GMT - Twilio-Concurrent-Requests: "1" - Twilio-Request-Duration: "0.080" - Twilio-Request-Id: RQb54d7f05d29e83bc89889cc136bcd99d - X-Api-Domain: api.twilio.com - X-Home-Region: us1 - X-Powered-By: AT-5000 - X-Shenanigans: none - body: '{"code": 21608, "message": "The number +917000XXXX is unverified. Trial accounts cannot send messages to unverified numbers; verify +917000XXXX at twilio.com/user/account/phone-numbers/verified, or purchase a Twilio number to send messages to unverified numbers", "more_info": "https://www.twilio.com/docs/errors/21608", "status": 400}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 0001-01-01T00:00:00Z - objects: [] - created: 1699954041 - reqTimestampMock: 2023-11-14T14:57:20.914415283+05:30 - resTimestampMock: 2023-11-14T14:57:21.298027703+05:30 diff --git a/fastapi-twilio/keploy/test-set-0/tests/test-1.yaml b/fastapi-twilio/keploy/test-set-0/tests/test-1.yaml deleted file mode 100755 index c088b98..0000000 --- a/fastapi-twilio/keploy/test-set-0/tests/test-1.yaml +++ /dev/null @@ -1,58 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-1 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/send-sms/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "75" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: c871b715-7aae-46b6-8e0d-1341aa426624 - User-Agent: PostmanRuntime/7.34.0 - body: |- - { - "Body": "Test, testtt, testttttttssss :)", - "To": "+91700004379" - } - body_type: "" - timestamp: 2023-11-14T14:56:25.800517709+05:30 - resp: - status_code: 200 - header: - Content-Length: "73" - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:26:25 GMT - Server: uvicorn - body: '{"message":"Failed to send SMS. Please check the provided phone number."}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2023-11-14T14:56:32.013566624+05:30 - objects: [] - assertions: - noise: - header.Date: [] - created: 1699953992 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/send-sms/ \ - --header 'User-Agent: PostmanRuntime/7.34.0' \ - --header 'Accept: */*' \ - --header 'Postman-Token: c871b715-7aae-46b6-8e0d-1341aa426624' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'Content-Type: application/json' \ - --data '{ - "Body": "Test, testtt, testttttttssss :)", - "To": "+91700004379" - }' diff --git a/fastapi-twilio/keploy/test-set-0/tests/test-2.yaml b/fastapi-twilio/keploy/test-set-0/tests/test-2.yaml deleted file mode 100755 index bb9db1e..0000000 --- a/fastapi-twilio/keploy/test-set-0/tests/test-2.yaml +++ /dev/null @@ -1,58 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-2 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/send-sms/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "76" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: a3780363-733f-4c88-915b-d4d69384822c - User-Agent: PostmanRuntime/7.34.0 - body: |- - { - "Body": "Test, testtt, testttttttssss :)", - "To": "+917000043797" - } - body_type: "" - timestamp: 2023-11-14T14:56:33.722179585+05:30 - resp: - status_code: 200 - header: - Content-Length: "36" - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:26:33 GMT - Server: uvicorn - body: '{"message":"SMS sent successfully!"}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2023-11-14T14:56:37.588988851+05:30 - objects: [] - assertions: - noise: - header.Date: [] - created: 1699953997 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/send-sms/ \ - --header 'Content-Type: application/json' \ - --header 'User-Agent: PostmanRuntime/7.34.0' \ - --header 'Accept: */*' \ - --header 'Postman-Token: a3780363-733f-4c88-915b-d4d69384822c' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --data '{ - "Body": "Test, testtt, testttttttssss :)", - "To": "+917000043797" - }' diff --git a/fastapi-twilio/keploy/test-set-0/tests/test-3.yaml b/fastapi-twilio/keploy/test-set-0/tests/test-3.yaml deleted file mode 100755 index 3a01fb6..0000000 --- a/fastapi-twilio/keploy/test-set-0/tests/test-3.yaml +++ /dev/null @@ -1,58 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-3 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/send-sms/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "74" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: 5e8c1a07-c35d-4816-8b32-c6bcfd28d94d - User-Agent: PostmanRuntime/7.34.0 - body: |- - { - "Body": "Test, testtt, testttttttssss :)", - "To": "+9170000437" - } - body_type: "" - timestamp: 2023-11-14T14:57:19.642139975+05:30 - resp: - status_code: 200 - header: - Content-Length: "73" - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:27:18 GMT - Server: uvicorn - body: '{"message":"Failed to send SMS. Please check the provided phone number."}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2023-11-14T14:57:23.973137683+05:30 - objects: [] - assertions: - noise: - header.Date: [] - created: 1699954043 -curl: |- - curl --request POST \ - --url http://127.0.0.1:8000/send-sms/ \ - --header 'Accept: */*' \ - --header 'Postman-Token: 5e8c1a07-c35d-4816-8b32-c6bcfd28d94d' \ - --header 'Host: 127.0.0.1:8000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'Content-Type: application/json' \ - --header 'User-Agent: PostmanRuntime/7.34.0' \ - --data '{ - "Body": "Test, testtt, testttttttssss :)", - "To": "+9170000437" - }' diff --git a/fastapi-twilio/keploy/testReports/report-1.yaml b/fastapi-twilio/keploy/testReports/report-1.yaml deleted file mode 100755 index acf2233..0000000 --- a/fastapi-twilio/keploy/testReports/report-1.yaml +++ /dev/null @@ -1,284 +0,0 @@ -version: api.keploy.io/v1beta1 -name: report-1 -status: PASSED -success: 3 -failure: 0 -total: 3 -tests: - - kind: Http - name: report-1 - status: PASSED - started: 1699954104 - completed: 1699954106 - test_case_path: /home/shashwat/test/python-twilio/keploy/test-set-0 - mock_path: "" - test_case_id: test-1 - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/send-sms/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "75" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: c871b715-7aae-46b6-8e0d-1341aa426624 - User-Agent: PostmanRuntime/7.34.0 - body: |- - { - "Body": "Test, testtt, testttttttssss :)", - "To": "+91700004379" - } - body_type: "" - timestamp: 0001-01-01T00:00:00Z - resp: - status_code: 200 - header: - Content-Length: "73" - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:26:25 GMT - Server: uvicorn - body: '{"message":"Failed to send SMS. Please check the provided phone number."}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 0001-01-01T00:00:00Z - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Length - value: - - "73" - actual: - key: Content-Length - value: - - "73" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Tue, 14 Nov 2023 09:26:25 GMT - actual: - key: Date - value: - - Tue, 14 Nov 2023 09:28:24 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - body_result: - - normal: true - type: JSON - expected: '{"message":"Failed to send SMS. Please check the provided phone number."}' - actual: '{"message":"Failed to send SMS. Please check the provided phone number."}' - dep_result: [] - - kind: Http - name: report-1 - status: PASSED - started: 1699954106 - completed: 1699954107 - test_case_path: /home/shashwat/test/python-twilio/keploy/test-set-0 - mock_path: "" - test_case_id: test-2 - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/send-sms/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "76" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: a3780363-733f-4c88-915b-d4d69384822c - User-Agent: PostmanRuntime/7.34.0 - body: |- - { - "Body": "Test, testtt, testttttttssss :)", - "To": "+917000043797" - } - body_type: "" - timestamp: 0001-01-01T00:00:00Z - resp: - status_code: 200 - header: - Content-Length: "36" - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:26:33 GMT - Server: uvicorn - body: '{"message":"SMS sent successfully!"}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 0001-01-01T00:00:00Z - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Tue, 14 Nov 2023 09:26:33 GMT - actual: - key: Date - value: - - Tue, 14 Nov 2023 09:28:26 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - - normal: true - expected: - key: Content-Length - value: - - "36" - actual: - key: Content-Length - value: - - "36" - body_result: - - normal: true - type: JSON - expected: '{"message":"SMS sent successfully!"}' - actual: '{"message":"SMS sent successfully!"}' - dep_result: [] - - kind: Http - name: report-1 - status: PASSED - started: 1699954107 - completed: 1699954108 - test_case_path: /home/shashwat/test/python-twilio/keploy/test-set-0 - mock_path: "" - test_case_id: test-3 - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://127.0.0.1:8000/send-sms/ - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Connection: keep-alive - Content-Length: "74" - Content-Type: application/json - Host: 127.0.0.1:8000 - Postman-Token: 5e8c1a07-c35d-4816-8b32-c6bcfd28d94d - User-Agent: PostmanRuntime/7.34.0 - body: |- - { - "Body": "Test, testtt, testttttttssss :)", - "To": "+9170000437" - } - body_type: "" - timestamp: 0001-01-01T00:00:00Z - resp: - status_code: 200 - header: - Content-Length: "73" - Content-Type: application/json - Date: Tue, 14 Nov 2023 09:27:18 GMT - Server: uvicorn - body: '{"message":"Failed to send SMS. Please check the provided phone number."}' - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 0001-01-01T00:00:00Z - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Tue, 14 Nov 2023 09:27:18 GMT - actual: - key: Date - value: - - Tue, 14 Nov 2023 09:28:27 GMT - - normal: true - expected: - key: Server - value: - - uvicorn - actual: - key: Server - value: - - uvicorn - - normal: true - expected: - key: Content-Length - value: - - "73" - actual: - key: Content-Length - value: - - "73" - body_result: - - normal: true - type: JSON - expected: '{"message":"Failed to send SMS. Please check the provided phone number."}' - actual: '{"message":"Failed to send SMS. Please check the provided phone number."}' - dep_result: [] -test_set: test-set-0 diff --git a/fastapi-twilio/main.py b/fastapi-twilio/main.py index 82800cd..4cbb40c 100644 --- a/fastapi-twilio/main.py +++ b/fastapi-twilio/main.py @@ -3,18 +3,17 @@ from dotenv import load_dotenv from pydantic import BaseModel import os +import asyncio - +# Load environment variables from a .env file load_dotenv() - class Message(BaseModel): Body: str To: str app = FastAPI() - @app.post('/send-sms/') def send_sms(data: Message): twilio_account_sid = os.getenv('TWILIO_ACCOUNT_SID') @@ -37,3 +36,10 @@ def send_sms(data: Message): return {"message": "Failed to send SMS. Please check the provided phone number."} except Exception as e: return {"message": str(e)} + +# Graceful shutdown +@app.on_event("shutdown") +async def shutdown_event(): + print("Shutting down gracefully...") + # Perform any additional cleanup here if needed + # For example, closing database connections or other resources \ No newline at end of file diff --git a/fastapi-twilio/requirements.txt b/fastapi-twilio/requirements.txt index d86cb8b..7a9ca73 100644 --- a/fastapi-twilio/requirements.txt +++ b/fastapi-twilio/requirements.txt @@ -26,3 +26,28 @@ typing_extensions==4.8.0 urllib3==2.0.7 uvicorn==0.24.0.post1 yarl==1.9.2 +blinker==1.5 +chardet==5.1.0 +configobj==5.0.8 +cryptography==38.0.4 +httplib2==0.20.4 +Jinja2==3.1.2 +jsonpatch==1.32 +jsonpointer==2.3 +jsonschema==4.10.3 +markdown-it-py==2.1.0 +MarkupSafe==2.1.2 +mdurl==0.1.2 +netifaces==0.11.0 +oauthlib==3.2.2 +Pygments==2.14.0 +pyparsing==3.0.9 +pyrsistent==0.18.1 +pyserial==3.5 +PySimpleSOAP==1.16.2 +python-debian==0.1.49 +python-debianbts==4.0.1 +PyYAML==6.0 +rich==13.3.1 +six==1.16.0 +ssh-import-id==5.10 diff --git a/flask-mongo/.coverage b/flask-mongo/.coverage deleted file mode 100644 index b9fdbfc3ab404e8c0cde6193a1f517351896e37a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 53248 zcmeI)+lw1j90%~3Oqw*=EK@1lxGrVSOWiKrY+Nje^+8v=V72z5RUZV?lgY{M*tw)L zlkVya-U+l#~WLOZg3PpBPbbtBc=lL1yAR)grC63GNb=@YBf6;Y2Tsf2?dEv+(mvUU%$WMcP?7G>b zE(h_BRA)xcHJYUAdiLe6>R0}X7^GZ@!|?nS!9h?9I5JbHzJ5^Gs8y<+@Ulbiw;Hk= z`SEsxD!;Kt50$T8*k7zJF6uWf#|?#f8cjP2`zxi9M$_Ltrs?qU@$H6t$!H_tUgS8! zZ^vDRQ;Vc>s5KAwnRO+*GUS(PUV7)(wf8&RVHZ-B=vgbox!8vDRNL_vQ=5>cWD4trRz-w6@Zx z;z$$9YI2WZG&|%f8FqtgAbHdvnWY$vl35=~k5D+ZVxhXeFfN?*yvAC(vcFf%7prq~ zdN1h_JTCEl-$)R=XV3*6mYr?tRV=Lz|{mp0>gh*`{pQ690f{8u|*}M z?s`$(s(&2P&k)qZZQ1eaC;e^D@nws)rQ2~-SnKRYTfSFsJ2JdfbA4~quQ|RYox1FF z=;sJN$Wcy=?@|Hz`+vhcq?w1zi{=m0Q^klB0uX=z z1Rwwb2tWV=5P$##AfRcd^1V6z$u6^#3wGm7o_+)H$#NRH{?DDu_l}gFLU#S@fBgO* z+B*aw009U<00Izz00bZa0SG`~q6G}y&}RAjf8G37qZ<|oKmY;|fB*y_009U<00Izz z00bsbz%XV@$^ZY~)Xaa(Kg^pG7$ic100bZa0SG_<0uX=z1Rwwb2u!*_#mMWWmyBQU z{8;?&%uh2p+Ilhf^PPKFf2$Vse5rKcgr5BW|832@Z~kT8o^%kz2LT8`00Izz00bZa z0SG_<0uY!2fdYL1pc_W~l*{Gm6M*>pf9=2&#EuXl009U<00Izz00bZa0SG_<0#hu& z-~Z$Ke~KFbLWckZAOHafKmY;|fB*y_0D-9xNdEu-F8}@iJ@f8Vgp42|009U<00Izz b00bZa0SG_<0+TOb81$?EMvfo&_y7L~KzQX( diff --git a/flask-mongo/.coveragerc b/flask-mongo/.coveragerc deleted file mode 100644 index 387d12b..0000000 --- a/flask-mongo/.coveragerc +++ /dev/null @@ -1,4 +0,0 @@ -[run] -omit = - /usr/* -sigterm = true \ No newline at end of file diff --git a/flask-mongo/README.md b/flask-mongo/README.md index 526fad3..5239c2b 100644 --- a/flask-mongo/README.md +++ b/flask-mongo/README.md @@ -1,6 +1,7 @@ +# Flask-Mongo Sample Application + This application is a simple student management API built using Python's Flask framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on student records. The API supports CORS (Cross-Origin Resource Sharing) to facilitate cross-domain requests. -## Table of Contents # Introduction @@ -10,10 +11,18 @@ This application is a simple student management API built using Python's Flask f - Install WSL (`wsl --install`) for Windows Windows. -## Optional 🛠️ +#### Optional 🛠️ - Install Colima( `brew install colima && colima start` ) for MacOS MacOs. +## Install Keploy + +- Install Keploy CLI using the following command: + +```bash +curl -O -L https://keploy.io/install.sh && source install.sh +``` + ## Get Started! 🎬 ## Setup the MongoDB Database 📦 @@ -34,40 +43,16 @@ docker run -p 27017:27017 -d --network backend --name mongo mongo ```bash git clone https://github.com/keploy/samples-python.git && cd samples-python/flask-mongo +pip3 install -r requirements.txt ``` ## Installation 📥 -Depending on your OS, choose your adventure: - --
- Linux Linux or Windows Windows - - Alright, let's equip ourselves with the **latest Keploy binary**: - - ```bash - curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp - - sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy - ``` - - If everything goes right, your screen should look a bit like this: - - Moving on... -
- Run App with Docker Container Docker - - #### Add alias for Keploy: - - ```bash - alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' - ``` - - ### Lights, Camera, Record! 🎥 + ### With Docker 🎥 Build the app image: - ```bash + ```sh docker build -t flask-app:1.0 . ``` @@ -88,7 +73,13 @@ Depending on your OS, choose your adventure: **1. Make a POST request** ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + curl -X POST -H "Content-Type: application/json" -d '{"student_id": "12345", "name": "John Doe", "age": 20}' http://localhost:6000/students + ``` + + Let's add one more student: + + ```sh + curl -X POST -H "Content-Type: application/json" -d '{"student_id": "12346", "name": "Alice Green", "age": 22}' http://localhost:6000/students ``` **2. Make a GET request** @@ -226,12 +217,9 @@ Depending on your OS, choose your adventure: Happy coding! ✨👩‍💻👨‍💻✨ -
-
- -
- Run App on 🐧 Linux +--- + ## Running In Linux/WSL We'll be running our sample application right on Linux, but just to make things a tad more thrilling, we'll have the database (PostgreSQL) chill on Docker. Ready? Let's get the party started!🎉 ### 📼 Roll the Tape - Recording Time! @@ -262,205 +250,14 @@ Depending on your OS, choose your adventure: **1. Make a POST request** - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **2. Make a GET request** - - ```bash - curl http://localhost:6000/students - ``` - - **3. Make a PUT request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 - ``` - - **4. Make a GET request** - - ```bash - curl http://localhost:6000/students/12345 - ``` - - **5. Make a DELETE request** - - ```bash - curl -X DELETE http://localhost:6000/students/12345 - ``` - - Give yourself a pat on the back! With that simple spell, you've conjured up a test case with a mock! Explore the **Keploy directory** and you'll discover your handiwork in `test-1.yml` and `mocks.yml`. - - ```yaml - version: api.keploy.io/v1beta2 - kind: Http - name: test-1 - spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:6000/students - header: - Accept: "*/*" - Content-Length: "56" - Content-Type: application/json - Host: localhost:6000 - User-Agent: curl/7.81.0 - body: '{"student_id": "12344", "name": "John Doeww", "age": 10}' - body_type: "" - timestamp: 2023-11-13T13:02:32.241333562Z - resp: - status_code: 200 - header: - Content-Length: "48" - Content-Type: application/json - Date: Mon, 13 Nov 2023 13:02:32 GMT - Server: Werkzeug/2.2.2 Python/3.9.18 - body: | - { - "message": "Student created successfully" - } - body_type: "" - status_message: "" - proto_major: 0 - proto_minor: 0 - timestamp: 2023-11-13T13:02:34.752123715Z - objects: [] - assertions: - noise: - - header.Date - created: 1699880554 - curl: |- - curl --request POST \ - --url http://localhost:6000/students \ - --header 'Host: localhost:6000' \ - --header 'User-Agent: curl/7.81.0' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --data '{"student_id": "12344", "name": "John Doeww", "age": 10}' - ``` - - This is how `mocks.yml` generated would look like:- - - ```yaml - version: api.keploy.io/v1beta2 - kind: Mongo - name: mocks - spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }], checksum: 0 }' - requests: - - header: - length: 187 - requestId: 2127584089 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"find":"students","filter":{"student_id":"12345"},"projection":{"_id":{"$numberInt":"0"}},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"vPKsEFRdTLytlbnyVimqIA==","subType":"04"}}},"$db":"studentsdb"} }' - checksum: 0 - read_delay: 3469848802 - responses: - - header: - length: 166 - requestId: 154 - responseTo: 2127584089 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"student_id":"12345","name":"John Doe","age":{"$numberInt":"20"}}],"id":{"$numberLong":"0"},"ns":"studentsdb.students"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 869555 - created: 1699880576 - reqTimestampMock: 2023-11-13T13:02:56.385067848Z - resTimestampMock: 2023-11-13T13:02:56.386374941Z + ```bash + curl -X POST -H "Content-Type: application/json" -d '{"student_id": "12345", "name": "John Doe", "age": 20}' http://localhost:6000/students ``` - Want to see if everything works as expected? - - #### Run Tests - - Time to put things to the test 🧪 + Let's add one more student: - ```shell - keploy test -c "python3 app.py" --delay 10 - ``` - - > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. - - Final thoughts? Dive deeper! Try different API calls, tweak the DB response in the `mocks.yml`, or fiddle with the request or response in `test-x.yml`. Run the tests again and see the magic unfold!✨👩‍💻👨‍💻✨ - - ## Wrapping it up 🎉 - - Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible. 😊🚀 - - Happy coding! ✨👩‍💻👨‍💻✨ -
- -
- -
- --
- MacOS MacOs - - Dive straight in, but first in case you're using **Keploy** with **Colima**, give it a gentle nudge with (`colima start`). Let's make sure it's awake and ready for action! - - ### Add alias for Keploy 🐰: - - For the sake of convenience (and a bit of Mac magic 🪄), let's set up a shortcut for Keploy: - - ### Use Keploy with Docker-Desktop - - Note: To run Keploy on MacOS through [Docker](https://docs.docker.com/desktop/release-notes/#4252) the version must be `4.25.2` or above. - - #### Creating Docker Volume - - ```bash - docker volume create --driver local --opt type=debugfs --opt device=debugfs debugfs - ``` - - ```bash - alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v debugfs:/sys/kernel/debug:rw -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' - ``` - - ### Use Keploy with Colima - - ```bash - alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' - ``` - - ### Lights, Camera, Record! 🎥 - - Build the app image: - - ```bash - docker build -t flask-app:1.0 . - ``` - - Capture the test-cases- - - ```shell - keploy record -c "docker run -p 6000:6000 --name DjangoApp --network backend --name flask-app flask-app:1.0" - ``` - - 🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! - - Let's make URLs short and sweet: - - ### Generate testcases - - To generate testcases we just need to **make some API calls.** - - **1. Make a POST request** - - ```bash - curl -X PUT -H "Content-Type: application/json" -d '{"name": "Jane Smith", "age": 21}' http://localhost:6000/students/12345 + ```sh + curl -X POST -H "Content-Type: application/json" -d '{"student_id": "12346", "name": "Alice Green", "age": 22}' http://localhost:6000/students ``` **2. Make a GET request** @@ -577,16 +374,19 @@ Depending on your OS, choose your adventure: reqTimestampMock: 2023-11-13T13:02:56.385067848Z resTimestampMock: 2023-11-13T13:02:56.386374941Z ``` + + On terminal we can see the testcases generated - - Want to see if everything works as expected? + ![keploy testcases](./img/testcases.png) #### Run Tests Time to put things to the test 🧪 ```shell - keploy test -c "sudo docker run -p 6000:6000 --rm --network backend --name flask-app flask-app:1.0" --delay 10 + keploy test -c "python3 app.py" --delay 10 ``` + ![keploy testrun](./img/testrun-with-coverage.png) > The `--delay` flag? Oh, that's just giving your app a little breather (in seconds) before the test cases come knocking. @@ -594,7 +394,6 @@ Depending on your OS, choose your adventure: ## Wrapping it up 🎉 - Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 + Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible. 😊🚀 - Happy coding! ✨👩‍💻👨‍💻✨ -
\ No newline at end of file + Happy coding! ✨👩‍💻👨‍💻✨ \ No newline at end of file diff --git a/flask-mongo/__pycache__/app.cpython-310.pyc b/flask-mongo/__pycache__/app.cpython-310.pyc deleted file mode 100644 index e502979d3897a6d6fd44c61ea39de4daa6ed4ba8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2049 zcmZWqOK%iM5T5SodF<@N#x@W0Tp~mmB(sDI5<&JR9+!%6NGq)Q6grG?vd3Cd{B3a{(gxtse%&<*UI}%E&@^K9`|{Wk&N*08SOTN$7`_H6iptjI^C9N@j8qPqQ1Mx8@xFny!DLo1-|%$ z1A52i@?&%P5?{9RB`aUy$LI1B{G^pH&*i7)@>PD?%2!0h&pe@0!~Su8mY?J2`Gsfb zPkYO@_~I+@*oj@^-Om&C!~{}29SNmPu&b&v>+i?J)IYDvL3J|sYgh9IpP2Gl0J1@wg zGj%4w=qmPf)#2`QIwhLEa3|!DOsQs^X>USz{R6_i=M;LsPq&;n*fgHbbS_Mt3zf=j zsI#hkN#z1qmW$AhSGVDT?No|H3*J_v6ns_vQJ(L|6rZRRcx7nDU;PH^aUk)9CL9Re zLv&4)R(TE(f?X2NBa}y^I4%j3+uV46!giz&pzIOGlmq^}p6T zMX5V!=Mh*@9krJX%g%bWSLRj1VVxAiT&T6-KEPIX`pET~C1uSL0uT?c4fjob=1dQ7 zXo6YQfG(sy^@;ya#7+@;!M^R|jqP`!ryzyInn8aTCIf(d2LHPA&GM8?oEKCBo+7orjreA`eNPTW8ft5GiDp(FS28BH%HJ{%&~k5(vjDZ-cON z8_|Kc-7)UNN82fZ{Wl*L5-c?~1b>FfJOt5W3_(NIKqh=}l7pML3VIUtF69VNJ8jt=%eCC-!)XS|5oI-D@H1}7SL!gs!g z;x%R8F-Ukj?vXtwZf+jI@ff^QUW9JUE-9fUI%GT{WhKX#x53wTS?PAa8kM|VNm#Vg z$4NO5s=X(qXcq|=*-vmtE}@NCQjCTWs_!L5_9rOCHJb(UI9_V0i)Oku@-c=?tEhO^ z&mibixKq#4p|lo&1NBT= z_Ta)YDMYVlT*yYlP|5hI{r51G@60^(WHr*lRuh|G7V6oHT{$X`IBB!iCTw^c0%Mem kJBYrz0^N$!AovUE3bc@fKwd;zHE0pEg@}Y~g|OHE0^1|^1poj5 diff --git a/flask-mongo/__pycache__/test_app.cpython-310-pytest-8.1.1.pyc b/flask-mongo/__pycache__/test_app.cpython-310-pytest-8.1.1.pyc deleted file mode 100644 index ca0d856dc4193768233b03b4fada6881d7496a87..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 2471 zcma)8PjB2r6!+L(d-iYA6xs$_SR!aym1OCK1FBF&K`4hThbBU-kgTa^l6vE{&CD!O zR_Q6dR(ydTHpiU!8t@h7$|+wV5`y=}yU8YLQJu{5y!rd)_xsKB=FMi!foJdA`#XOG zj`KG<^N$bCIuvyXhC7_3PM_GfJM>(KI77c*A!Sd{51_|Q!(rGDZJU?UVYOc!*7~*S zn0mhsWBjx+Z1$VP`N8289=vpTAc8^b$m=hNMIP?C^05deH;!R_PM+G*p{Edm)9Vo9 zv7+d>rcy8+KR4A)wwuJ8dAtW*^v7od5$g>e4tC<;|x~r)3tlgwk6~?QOD*?FtzaSabGZ-GlN3iuwwS zb|&Q5Idmd8$DuQDB3FAy==-|DU1;%-z(xVof=Ou4?7%i&Z)@Cwldi>in!=fqJnK-2 z$1rsb`$ut_h)kOhog~|pNR?T*7#$4(6N#ai&_X4osVL2)J|V_eBHcN0WDB~_HoC)1 zcjNB15>j>5J}a{Bclmyn=8S{ShD9pWYH^^S=UI0rg@dmS^K3U?P4k$gT^kKXS{%Rz zLT?vUSXH60YJ?K%wn&SN-@gLdnjLu!Iy|6-4kJUj5IhtQKtg&QSK_h|zRnBTfT}$~ zX%?`DYQZE1e*-*)tHIuPuI@b>bZL8p3PH5ne+?Cs2lrmPFD!2Z!u>YiK+H1?xno!qmA?u}li2 z_^j4tMbgCq3TYasJUjghVo}RraItnQ1=E7J)hLdIQahtGJ?I3bGW;S}+SHi>CiVBf zj#z5yK)D{ND9*VswCvf)jL(^79Zxo4S@{tdL#0qfp219neh$(_j5#W|jWDwJpkGli zHL?iQE|GEjI>48wTml+dsX(znuR~?mGCd#>UI!1rB*z3npHvRXAmHv4{>l|*sCvU+zr+`bR?exBW_ zdhe`(cXyUJO%>CI;8DU)i2M}7I9s}qWEVT3Yuwl_KtP~El;rsKxxTaZXxf1!$eS=< z-bV8Ym=0fQ&`5^3Pi& zIydRTBn#VpSjxh-NKnK71KZrBUZ-kk6lH8EqR7-D z`0VgeiuFbmVFoIDEJ$btdk6~_C_)w?LRn;3#1>+N)M|H?$35=pZmMdq zJaSgfHsS}e7%#ozH{cg~%gVoC3BkS9Gxm%fBYIr7>(=Aet#eLQJ6~9+6L|K%y}$Fj zN6263%svh{8&K3X7*04%Nf+N%N(Zz{Dc0@O8rWTX;B+11)70&{(C(z(!0-B$d{4N` zy;p>Lg7n#u-K~i__xCK>7G&HwCNPV>FePB8uny@2w6vq52&~dAA|3CRwdYYUiJ#~3 z9(1uEw)-O1&v=Z3XCDik4Jhg{7(u#}ldi=nw_cI1&28?$+o_U)6n)OX_jrxh;qCJV zZ^E1Lg%>1PESENg(wmXmdmd#`Pso@;%;|%58_E+X>MJmsjOj5sBq8kMkn~AtY5NF$ zN4wmD7Uu|T=t0dJ`)1Dsma#jVqea;1dYq>z>?z5!fJxj&+0d|l7^jKIbm^m$WIc(5 zluH+*!vSC-F_qFcPzhPON=H(k(9%&N-8mt05xUQwwg;JR$L%d8q-v}EsL0yi<@;Hh zM;!cUP^3bw6$g4Z&)PdFY*jiQrCGQn@}~`S7r%&m==-5#NPo=VKi9#_T{yw zgXWe;m=Hj-{MS%HX>j|E_0n+Gr`$QD+1{FD(j4D zxM&L{GP<$3o2VB2MJ)uYrJ?Zz)TBVKFgvKFPl>6q0GWxqjV@Ltn8l9@&gzm@1nVFrW&~$JWi|%n~$*b5+W-G5ttuF zX=)%*@58VOCQZQPE*-7D6_dG1S5QGv4JsTedLqEr)^DpQvOeuw+}uyxe`9e5LPU&g zK*Zs-DMq}Gn4$M0NYR1ckzI-M5m68K;ZnxmPt!Bi=$tk2>`pJuvW8cN;9)~?p5w~XcbZ}1DRa5s!J0VoE5tyt{S ICUyS#7tjhZUjP6A diff --git a/flask-mongo/__pycache__/test_keploy.cpython-310-pytest-8.1.1.pyc b/flask-mongo/__pycache__/test_keploy.cpython-310-pytest-8.1.1.pyc deleted file mode 100644 index f77eaa007830cece0fdc1e3edd2404b67b75e3a8..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 657 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

#{k=xd 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�Lr- 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 NwuZiXm8uQ${{WHpcX$8* literal 0 HcmV?d00001 diff --git a/flask-mongo/img/testrun-with-coverage.png b/flask-mongo/img/testrun-with-coverage.png new file mode 100644 index 0000000000000000000000000000000000000000..2f3ee30804c1f550e2017b9bb5f28d9a260b4a4a GIT binary patch literal 160233 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 DV<-Nt literal 0 HcmV?d00001 diff --git a/flask-mongo/keploy.yml b/flask-mongo/keploy.yml new file mode 100755 index 0000000..e71edbf --- /dev/null +++ b/flask-mongo/keploy.yml @@ -0,0 +1,43 @@ +path: "" +appId: 0 +appName: "" +command: python3 app.py +port: 0 +dnsPort: 26789 +proxyPort: 16789 +debug: false +disableTele: false +disableANSI: false +containerName: "" +networkName: "" +buildDelay: 30 +test: + selectedTests: {} + globalNoise: + global: {} + test-sets: {} + delay: 5 + apiTimeout: 5 + skipCoverage: false + coverageReportPath: "" + ignoreOrdering: true + mongoPassword: default@123 + language: "" + removeUnusedMocks: false + fallBackOnMiss: false + jacocoAgentPath: "" + basePath: "" + mocking: true + ignoredTests: {} +record: + filters: [] + recordTimer: 0s +configPath: "" +bypassRules: [] +generateGithubActions: true +keployContainer: keploy-v2 +keployNetwork: keploy-network +cmdType: native +inCi: false + +# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file. diff --git a/flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml b/flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml deleted file mode 100644 index c4c5d3c..0000000 --- a/flask-mongo/keploy/reports/test-run-0/test-set-0-report.yaml +++ /dev/null @@ -1,446 +0,0 @@ -version: api.keploy.io/v1beta1 -name: test-set-0-report -status: FAILED -success: 0 -failure: 4 -total: 4 -tests: - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873653 - completed: 1713873653 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-1 - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "59" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title": "Task 6","description": "Description for Task 6"}' - timestamp: 2024-04-22T16:38:39.232565209+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "267" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:08:39 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "tasks": [ - { - "description": "should update", - "id": "6626362fc7c5eddf174c88e4", - "title": "Updated" - }, - { - "description": "Should work", - "id": "66263667c7c5eddf174c88e5", - "title": "Let's Check another time" - } - ] - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:38:41.245704918+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:08:39 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:00:53 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - - normal: false - expected: - key: Content-Length - value: - - "267" - actual: - key: Content-Length - value: - - "191" - body_result: - - normal: true - type: JSON - expected: | - { - "tasks": [ - { - "description": "should update", - "id": "6626362fc7c5eddf174c88e4", - "title": "Updated" - }, - { - "description": "Should work", - "id": "66263667c7c5eddf174c88e5", - "title": "Let's Check another time" - } - ] - } - actual: | - {"tasks":[{"description":"should update","id":"6626362fc7c5eddf174c88e4","title":"Updated"},{"description":"Should work","id":"66263667c7c5eddf174c88e5","title":"Let's Check another time"}]} - dep_result: [] - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873653 - completed: 1713873653 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-2 - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "57" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title":"Hey, let''s Check","description":"It will work"}' - timestamp: 2024-04-22T16:39:05.814517536+05:30 - resp: - status_code: 201 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "81" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:09:05 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "id": "66264551a6e962a1cbd50429", - "message": "Task created successfully" - } - status_message: Created - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:39:07.866639952+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 201 - actual: 201 - headers_result: - - normal: false - expected: - key: Content-Length - value: - - "81" - actual: - key: Content-Length - value: - - "72" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:09:05 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:00:53 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - body_result: - - normal: false - type: JSON - expected: | - { - "id": "66264551a6e962a1cbd50429", - "message": "Task created successfully" - } - actual: | - {"id":"6627a2f5a20cac37a4bb3d0f","message":"Task created successfully"} - dep_result: [] - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873653 - completed: 1713873653 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-3 - req: - method: PUT - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "53" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title": "Updated again","description": "hey there"}' - timestamp: 2024-04-22T16:39:52.181533473+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "45" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:09:52 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "message": "Task updated successfully" - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:39:54.273657454+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - - normal: false - expected: - key: Content-Length - value: - - "45" - actual: - key: Content-Length - value: - - "40" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:09:52 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:00:53 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - body_result: - - normal: true - type: JSON - expected: | - { - "message": "Task updated successfully" - } - actual: | - {"message":"Task updated successfully"} - dep_result: [] - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873653 - completed: 1713873653 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-4 - req: - method: DELETE - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Host: localhost:5000 - Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6 - User-Agent: PostmanRuntime/7.32.1 - body: "" - timestamp: 2024-04-22T16:40:08.615353613+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "45" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:10:08 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "message": "Task deleted successfully" - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:40:10.646676187+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - - normal: false - expected: - key: Content-Length - value: - - "45" - actual: - key: Content-Length - value: - - "40" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:10:08 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:00:53 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - body_result: - - normal: true - type: JSON - expected: | - { - "message": "Task deleted successfully" - } - actual: | - {"message":"Task deleted successfully"} - dep_result: [] -test_set: test-set-0 diff --git a/flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml b/flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml deleted file mode 100644 index 61157f7..0000000 --- a/flask-mongo/keploy/reports/test-run-1/test-set-0-report.yaml +++ /dev/null @@ -1,446 +0,0 @@ -version: api.keploy.io/v1beta1 -name: test-set-0-report -status: FAILED -success: 0 -failure: 4 -total: 4 -tests: - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873824 - completed: 1713873824 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-1 - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "59" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title": "Task 6","description": "Description for Task 6"}' - timestamp: 2024-04-22T16:38:39.232565209+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "267" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:08:39 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "tasks": [ - { - "description": "should update", - "id": "6626362fc7c5eddf174c88e4", - "title": "Updated" - }, - { - "description": "Should work", - "id": "66263667c7c5eddf174c88e5", - "title": "Let's Check another time" - } - ] - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:38:41.245704918+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:08:39 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:03:44 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - - normal: false - expected: - key: Content-Length - value: - - "267" - actual: - key: Content-Length - value: - - "191" - body_result: - - normal: true - type: JSON - expected: | - { - "tasks": [ - { - "description": "should update", - "id": "6626362fc7c5eddf174c88e4", - "title": "Updated" - }, - { - "description": "Should work", - "id": "66263667c7c5eddf174c88e5", - "title": "Let's Check another time" - } - ] - } - actual: | - {"tasks":[{"description":"should update","id":"6626362fc7c5eddf174c88e4","title":"Updated"},{"description":"Should work","id":"66263667c7c5eddf174c88e5","title":"Let's Check another time"}]} - dep_result: [] - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873824 - completed: 1713873824 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-2 - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "57" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title":"Hey, let''s Check","description":"It will work"}' - timestamp: 2024-04-22T16:39:05.814517536+05:30 - resp: - status_code: 201 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "81" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:09:05 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "id": "66264551a6e962a1cbd50429", - "message": "Task created successfully" - } - status_message: Created - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:39:07.866639952+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 201 - actual: 201 - headers_result: - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:09:05 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:03:44 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - - normal: false - expected: - key: Content-Length - value: - - "81" - actual: - key: Content-Length - value: - - "72" - body_result: - - normal: false - type: JSON - expected: | - { - "id": "66264551a6e962a1cbd50429", - "message": "Task created successfully" - } - actual: | - {"id":"6627a3a0dcedca8503554d0d","message":"Task created successfully"} - dep_result: [] - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873824 - completed: 1713873824 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-3 - req: - method: PUT - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "53" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title": "Updated again","description": "hey there"}' - timestamp: 2024-04-22T16:39:52.181533473+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "45" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:09:52 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "message": "Task updated successfully" - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:39:54.273657454+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:09:52 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:03:44 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - - normal: false - expected: - key: Content-Length - value: - - "45" - actual: - key: Content-Length - value: - - "40" - body_result: - - normal: true - type: JSON - expected: | - { - "message": "Task updated successfully" - } - actual: | - {"message":"Task updated successfully"} - dep_result: [] - - kind: Http - name: test-set-0 - status: FAILED - started: 1713873824 - completed: 1713873824 - test_case_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0 - mock_path: /mnt/c/Users/swapn/Downloads/samples-python/flask-mongo-local/keploy/test-set-0/mocks.yaml - test_case_id: test-4 - req: - method: DELETE - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Host: localhost:5000 - Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6 - User-Agent: PostmanRuntime/7.32.1 - body: "" - timestamp: 2024-04-22T16:40:08.615353613+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "45" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:10:08 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "message": "Task deleted successfully" - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:40:10.646676187+05:30 - noise: - header.Date: [] - result: - status_code: - normal: true - expected: 200 - actual: 200 - headers_result: - - normal: false - expected: - key: Content-Length - value: - - "45" - actual: - key: Content-Length - value: - - "40" - - normal: true - expected: - key: Content-Type - value: - - application/json - actual: - key: Content-Type - value: - - application/json - - normal: true - expected: - key: Date - value: - - Mon, 22 Apr 2024 11:10:08 GMT - actual: - key: Date - value: - - Tue, 23 Apr 2024 12:03:44 GMT - - normal: true - expected: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - actual: - key: Server - value: - - Werkzeug/3.0.2 Python/3.10.12 - - normal: true - expected: - key: Access-Control-Allow-Origin - value: - - '*' - actual: - key: Access-Control-Allow-Origin - value: - - '*' - body_result: - - normal: true - type: JSON - expected: | - { - "message": "Task deleted successfully" - } - actual: | - {"message":"Task deleted successfully"} - dep_result: [] -test_set: test-set-0 diff --git a/flask-mongo/keploy/test-set-0/mocks.yaml b/flask-mongo/keploy/test-set-0/mocks.yaml deleted file mode 100644 index 8b4d319..0000000 --- a/flask-mongo/keploy/test-set-0/mocks.yaml +++ /dev/null @@ -1,319 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-0 -spec: - metadata: - operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo","version": "4.6.3"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "5.15.146.1-microsoft-standard-WSL2"},"platform": "CPython 3.10.12.final.0"}}, returnFieldsSelector: }' - type: config - requests: - - header: - length: 283 - requestId: 1804289383 - responseTo: 0 - Opcode: 2004 - message: - flags: 0 - collection_name: admin.$cmd - number_to_skip: 0 - number_to_return: -1 - query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo","version":"4.6.3"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"5.15.146.1-microsoft-standard-WSL2"},"platform":"CPython 3.10.12.final.0"}}' - return_fields_selector: "" - responses: - - header: - length: 329 - requestId: 238 - responseTo: 1804289383 - Opcode: 1 - message: - response_flags: 8 - cursor_id: 0 - starting_from: 0 - number_returned: 1 - documents: - - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784113763"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"18"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' - read_delay: 1010011 - created: 1713784113 - reqTimestampMock: 2024-04-22T16:38:33.762559618+05:30 - resTimestampMock: 2024-04-22T16:38:33.763749062+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-1 -spec: - metadata: - operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo","version": "4.6.3"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "5.15.146.1-microsoft-standard-WSL2"},"platform": "CPython 3.10.12.final.0"},"compression": []}, returnFieldsSelector: }' - type: config - requests: - - header: - length: 301 - requestId: 1714636915 - responseTo: 0 - Opcode: 2004 - message: - flags: 0 - collection_name: admin.$cmd - number_to_skip: 0 - number_to_return: -1 - query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo","version":"4.6.3"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"5.15.146.1-microsoft-standard-WSL2"},"platform":"CPython 3.10.12.final.0"},"compression":[]}' - return_fields_selector: "" - responses: - - header: - length: 329 - requestId: 242 - responseTo: 1714636915 - Opcode: 1 - message: - response_flags: 8 - cursor_id: 0 - starting_from: 0 - number_returned: 1 - documents: - - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784119236"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"22"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' - read_delay: 527460 - created: 1713784119 - reqTimestampMock: 2024-04-22T16:38:39.236318621+05:30 - resTimestampMock: 2024-04-22T16:38:39.236994457+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-2 -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"tasks","filter":{},"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }], checksum: 0 }' - requests: - - header: - length: 113 - requestId: 1957747793 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"find":"tasks","filter":{},"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' - checksum: 0 - read_delay: 336283 - responses: - - header: - length: 272 - requestId: 243 - responseTo: 1957747793 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":{"$oid":"6626362fc7c5eddf174c88e4"},"title":"Updated","description":"should update"},{"_id":{"$oid":"66263667c7c5eddf174c88e5"},"title":"Let''s Check another time","description":"Should work"}],"id":{"$numberLong":"0"},"ns":"task_manager.tasks"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 712174 - created: 1713784119 - reqTimestampMock: 2024-04-22T16:38:39.237446806+05:30 - resTimestampMock: 2024-04-22T16:38:39.238329738+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-3 -spec: - metadata: - operation: '{ OpMsg flags: 65536, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }], checksum: 0 }' - type: config - requests: - - header: - length: 134 - requestId: 846930886 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 65536 - sections: - - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }' - checksum: 0 - read_delay: 2621927 - responses: - - header: - length: 313 - requestId: 244 - responseTo: 846930886 - Opcode: 2013 - message: - flagBits: 2 - sections: - - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784123771"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"18"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 10005242839 - created: 1713784123 - reqTimestampMock: 2024-04-22T16:38:33.766550283+05:30 - resTimestampMock: 2024-04-22T16:38:43.772009113+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-4 -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }], checksum: 0 }' - type: config - requests: - - header: - length: 52 - requestId: 1714636915 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }' - checksum: 0 - read_delay: 10012944393 - responses: - - header: - length: 313 - requestId: 245 - responseTo: 1714636915 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784123781"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"19"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 458361 - created: 1713784123 - reqTimestampMock: 2024-04-22T16:38:43.781318376+05:30 - resTimestampMock: 2024-04-22T16:38:43.781975276+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-5 -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }], checksum: 0 }' - type: config - requests: - - header: - length: 65 - requestId: 1957747793 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }' - checksum: 0 - read_delay: 10012662732 - responses: - - header: - length: 314 - requestId: 249 - responseTo: 1957747793 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6626352423399d438e00b0cf"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1713784133794"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"19"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 430352 - created: 1713784133 - reqTimestampMock: 2024-04-22T16:38:53.794777057+05:30 - resTimestampMock: 2024-04-22T16:38:53.795333713+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-6 -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"insert":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }, { SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"66264551a6e962a1cbd50429"},"title":"Hey, let''s Check","description":"It will work"} ] }], checksum: 0 }' - requests: - - header: - length: 207 - requestId: 596516649 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"insert":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' - - '{ SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"66264551a6e962a1cbd50429"},"title":"Hey, let''s Check","description":"It will work"} ] }' - checksum: 0 - read_delay: 26577872780 - responses: - - header: - length: 45 - requestId: 256 - responseTo: 596516649 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 5437683 - created: 1713784145 - reqTimestampMock: 2024-04-22T16:39:05.816402038+05:30 - resTimestampMock: 2024-04-22T16:39:05.822001482+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-7 -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"update":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }, { SectionSingle identifier: updates , msgs: [ {"q":{"_id":{"$oid":"6626362fc7c5eddf174c88e4"}},"u":{"$set":{"title":"Updated again","description":"hey there"}},"multi":false,"upsert":false} ] }], checksum: 0 }' - requests: - - header: - length: 243 - requestId: 1102520059 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"update":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' - - '{ SectionSingle identifier: updates , msgs: [ {"q":{"_id":{"$oid":"6626362fc7c5eddf174c88e4"}},"u":{"$set":{"title":"Updated again","description":"hey there"}},"multi":false,"upsert":false} ] }' - checksum: 0 - read_delay: 46361192429 - responses: - - header: - length: 60 - requestId: 273 - responseTo: 1102520059 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"nModified":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 5673350 - created: 1713784192 - reqTimestampMock: 2024-04-22T16:39:52.183391788+05:30 - resTimestampMock: 2024-04-22T16:39:52.189223944+05:30 ---- -version: api.keploy.io/v1beta1 -kind: Mongo -name: mock-8 -spec: - metadata: - operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"delete":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }, { SectionSingle identifier: deletes , msgs: [ {"q":{"_id":{"$oid":"66263667c7c5eddf174c88e5"}},"limit":{"$numberInt":"1"}} ] }], checksum: 0 }' - requests: - - header: - length: 166 - requestId: 1365180540 - responseTo: 0 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"delete":"tasks","ordered":true,"lsid":{"id":{"$binary":{"base64":"2JJr5nwqRNe8aRUchma6xQ==","subType":"04"}}},"$db":"task_manager"} }' - - '{ SectionSingle identifier: deletes , msgs: [ {"q":{"_id":{"$oid":"66263667c7c5eddf174c88e5"}},"limit":{"$numberInt":"1"}} ] }' - checksum: 0 - read_delay: 16427108137 - responses: - - header: - length: 45 - requestId: 286 - responseTo: 1365180540 - Opcode: 2013 - message: - flagBits: 0 - sections: - - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' - checksum: 0 - read_delay: 1386879 - created: 1713784208 - reqTimestampMock: 2024-04-22T16:40:08.616520091+05:30 - resTimestampMock: 2024-04-22T16:40:08.61802554+05:30 diff --git a/flask-mongo/keploy/test-set-0/tests/test-1.yaml b/flask-mongo/keploy/test-set-0/tests/test-1.yaml deleted file mode 100644 index fae2cc0..0000000 --- a/flask-mongo/keploy/test-set-0/tests/test-1.yaml +++ /dev/null @@ -1,66 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-1 -spec: - metadata: {} - req: - method: GET - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "59" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title": "Task 6","description": "Description for Task 6"}' - timestamp: 2024-04-22T16:38:39.232565209+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "267" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:08:39 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "tasks": [ - { - "description": "should update", - "id": "6626362fc7c5eddf174c88e4", - "title": "Updated" - }, - { - "description": "Should work", - "id": "66263667c7c5eddf174c88e5", - "title": "Let's Check another time" - } - ] - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:38:41.245704918+05:30 - objects: [] - assertions: - noise: - header.Date: [] - created: 1713784121 -curl: |- - curl --request GET \ - --url http://localhost:5000/api/tasks \ - --header 'Host: localhost:5000' \ - --header 'User-Agent: PostmanRuntime/7.32.1' \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --header 'Connection: keep-alive' \ - --header 'Cache-Control: no-cache' \ - --header 'Postman-Token: 10512b5c-4da7-4ef3-b145-101cdd1357f1' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --data '{"title": "Task 6","description": "Description for Task 6"}' diff --git a/flask-mongo/keploy/test-set-0/tests/test-2.yaml b/flask-mongo/keploy/test-set-0/tests/test-2.yaml deleted file mode 100644 index 640154f..0000000 --- a/flask-mongo/keploy/test-set-0/tests/test-2.yaml +++ /dev/null @@ -1,56 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-2 -spec: - metadata: {} - req: - method: POST - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "57" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title":"Hey, let''s Check","description":"It will work"}' - timestamp: 2024-04-22T16:39:05.814517536+05:30 - resp: - status_code: 201 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "81" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:09:05 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "id": "66264551a6e962a1cbd50429", - "message": "Task created successfully" - } - status_message: Created - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:39:07.866639952+05:30 - objects: [] - assertions: - noise: - header.Date: [] - created: 1713784147 -curl: |- - curl --request POST \ - --url http://localhost:5000/api/tasks \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'User-Agent: PostmanRuntime/7.32.1' \ - --header 'Host: localhost:5000' \ - --header 'Cache-Control: no-cache' \ - --header 'Accept: */*' \ - --header 'Postman-Token: 7aabbe61-38ec-4169-a4d8-31cb3546ca01' \ - --header 'Content-Type: application/json' \ - --data '{"title":"Hey, let's Check","description":"It will work"}' diff --git a/flask-mongo/keploy/test-set-0/tests/test-3.yaml b/flask-mongo/keploy/test-set-0/tests/test-3.yaml deleted file mode 100644 index 3844c87..0000000 --- a/flask-mongo/keploy/test-set-0/tests/test-3.yaml +++ /dev/null @@ -1,55 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-3 -spec: - metadata: {} - req: - method: PUT - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Content-Length: "53" - Content-Type: application/json - Host: localhost:5000 - Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3 - User-Agent: PostmanRuntime/7.32.1 - body: '{"title": "Updated again","description": "hey there"}' - timestamp: 2024-04-22T16:39:52.181533473+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "45" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:09:52 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "message": "Task updated successfully" - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:39:54.273657454+05:30 - objects: [] - assertions: - noise: - header.Date: [] - created: 1713784194 -curl: |- - curl --request PUT \ - --url http://localhost:5000/api/tasks/6626362fc7c5eddf174c88e4 \ - --header 'Accept: */*' \ - --header 'Content-Type: application/json' \ - --header 'User-Agent: PostmanRuntime/7.32.1' \ - --header 'Host: localhost:5000' \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Cache-Control: no-cache' \ - --header 'Postman-Token: 89d42b67-eafb-474e-ac5a-1df4982a9fe3' \ - --header 'Connection: keep-alive' \ - --data '{"title": "Updated again","description": "hey there"}' diff --git a/flask-mongo/keploy/test-set-0/tests/test-4.yaml b/flask-mongo/keploy/test-set-0/tests/test-4.yaml deleted file mode 100644 index 9888fea..0000000 --- a/flask-mongo/keploy/test-set-0/tests/test-4.yaml +++ /dev/null @@ -1,51 +0,0 @@ -version: api.keploy.io/v1beta1 -kind: Http -name: test-4 -spec: - metadata: {} - req: - method: DELETE - proto_major: 1 - proto_minor: 1 - url: http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 - header: - Accept: '*/*' - Accept-Encoding: gzip, deflate, br - Cache-Control: no-cache - Connection: keep-alive - Host: localhost:5000 - Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6 - User-Agent: PostmanRuntime/7.32.1 - body: "" - timestamp: 2024-04-22T16:40:08.615353613+05:30 - resp: - status_code: 200 - header: - Access-Control-Allow-Origin: '*' - Content-Length: "45" - Content-Type: application/json - Date: Mon, 22 Apr 2024 11:10:08 GMT - Server: Werkzeug/3.0.2 Python/3.10.12 - body: | - { - "message": "Task deleted successfully" - } - status_message: OK - proto_major: 0 - proto_minor: 0 - timestamp: 2024-04-22T16:40:10.646676187+05:30 - objects: [] - assertions: - noise: - header.Date: [] - created: 1713784210 -curl: | - curl --request DELETE \ - --url http://localhost:5000/api/tasks/66263667c7c5eddf174c88e5 \ - --header 'Accept-Encoding: gzip, deflate, br' \ - --header 'Connection: keep-alive' \ - --header 'User-Agent: PostmanRuntime/7.32.1' \ - --header 'Accept: */*' \ - --header 'Cache-Control: no-cache' \ - --header 'Postman-Token: 0f3d6037-f57c-4fb3-be52-e6ffed1566e6' \ - --header 'Host: localhost:5000' \ diff --git a/flask-mongo/requirements.txt b/flask-mongo/requirements.txt index 7a03746..cbc61f9 100644 --- a/flask-mongo/requirements.txt +++ b/flask-mongo/requirements.txt @@ -1,4 +1,42 @@ Flask pymongo==4.4.1 Flask-Cors==3.0.10 -Werkzeug==2.2.2 \ No newline at end of file +Werkzeug==2.2.2 +annotated-types==0.7.0 +anyio==4.4.0 +certifi==2024.7.4 +charset-normalizer==3.3.2 +click==8.1.7 +coverage==7.6.0 +dnspython==2.6.1 +email_validator==2.2.0 +fastapi==0.111.1 +fastapi-cli==0.0.4 +h11==0.14.0 +httpcore==1.0.5 +httptools==0.6.1 +httpx==0.27.0 +idna==3.7 +Jinja2==3.1.4 +keploy==2.0.0a39 +markdown-it-py==3.0.0 +MarkupSafe==2.1.5 +mdurl==0.1.2 +pydantic==2.8.2 +pydantic_core==2.20.1 +Pygments==2.18.0 +python-dotenv==1.0.1 +python-multipart==0.0.9 +PyYAML==6.0.1 +requests==2.32.3 +rich==13.7.1 +shellingham==1.5.4 +sniffio==1.3.1 +starlette==0.37.2 +typer==0.12.3 +typing_extensions==4.12.2 +urllib3==2.2.2 +uvicorn==0.30.3 +uvloop==0.19.0 +watchfiles==0.22.0 +websockets==12.0 From 181110ec554329830a7cfb0044e990432d013415 Mon Sep 17 00:00:00 2001 From: Sarthak Shyngle <50234097+Sarthak160@users.noreply.github.com> Date: Sun, 4 Aug 2024 20:12:09 +0530 Subject: [PATCH 18/31] refactor: remove keployFlaskMiddleware (#27) Signed-off-by: Sarthak160 --- flask-mongo/app.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/flask-mongo/app.py b/flask-mongo/app.py index 31c1a76..6f7172f 100644 --- a/flask-mongo/app.py +++ b/flask-mongo/app.py @@ -2,14 +2,13 @@ from pymongo import MongoClient from flask_cors import CORS import collections.abc -from keploy import FlaskCoverageMiddleware + app = Flask(__name__) cors = CORS(app, resources={r"/api/*": {"origins": "*"}}) -app.wsgi_app = FlaskCoverageMiddleware(app.wsgi_app) # Connect to MongoDB -client = MongoClient('mongodb://localhost:27017/') +client = MongoClient('mongodb://mongo:27017/') db = client['studentsdb'] students_collection = db['students'] From b043a930f6dd6a8ce58a9dc50b59788eefa1bff0 Mon Sep 17 00:00:00 2001 From: Swapnoneel Saha <121167506+Swpn0neel@users.noreply.github.com> Date: Thu, 8 Aug 2024 11:40:27 +0530 Subject: [PATCH 19/31] added sanic+mongo sample app (#23) Signed-off-by: Swapnoneel Saha --- sanic-mongo/README.md | 122 +++++ sanic-mongo/keploy/test-set-0/mocks.yaml | 490 ++++++++++++++++++ .../keploy/test-set-0/tests/test-1.yaml | 42 ++ .../keploy/test-set-0/tests/test-2.yaml | 42 ++ .../keploy/test-set-0/tests/test-3.yaml | 42 ++ .../keploy/test-set-0/tests/test-4.yaml | 40 ++ .../keploy/test-set-0/tests/test-5.yaml | 38 ++ sanic-mongo/requirements.txt | 3 + sanic-mongo/server.py | 60 +++ 9 files changed, 879 insertions(+) create mode 100644 sanic-mongo/README.md create mode 100644 sanic-mongo/keploy/test-set-0/mocks.yaml create mode 100644 sanic-mongo/keploy/test-set-0/tests/test-1.yaml create mode 100644 sanic-mongo/keploy/test-set-0/tests/test-2.yaml create mode 100644 sanic-mongo/keploy/test-set-0/tests/test-3.yaml create mode 100644 sanic-mongo/keploy/test-set-0/tests/test-4.yaml create mode 100644 sanic-mongo/keploy/test-set-0/tests/test-5.yaml create mode 100644 sanic-mongo/requirements.txt create mode 100644 sanic-mongo/server.py diff --git a/sanic-mongo/README.md b/sanic-mongo/README.md new file mode 100644 index 0000000..f0cc267 --- /dev/null +++ b/sanic-mongo/README.md @@ -0,0 +1,122 @@ +This application is a simple movie management API built using Python's Sanic framework and MongoDB for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on Movie records. + +## Table of Contents + +# Introduction + +🪄 Dive into the world of Movie CRUD Apps and see how seamlessly Keploy integrated with [Sanic](hhttps://sanic.dev/en/) and [MongoDB](https://www.mongodb.com/). Buckle up, it's gonna be a fun ride! 🎢 + +## Pre-Requisite 🛠️ + +- Install WSL (`wsl --install`) for Windows Windows. + +## Optional 🛠️ + +- Install Colima( `brew install colima && colima start` ) for MacOS MacOs. + +## Installation 📥 + +Depending on your OS, choose your adventure: + +Alright, let's equip ourselves with the **latest Keploy binary**: + +```bash +curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp + +sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +``` + +#### Add alias for Keploy: + +```bash +alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' +``` + +Now head to the folder of the application and run + +``` +pip3 install -r requirements.txt +``` + +### Lights, Camera, Record! 🎥 + +Capture the test-cases- + +```shell +keploy record -c "python3 server.py" +``` + +🔥**Make some API calls**. Postman, Hoppscotch or even curl - take your pick! + +Let's make URLs short and sweet: + +### Generate testcases + +To generate testcases we just need to **make some API calls.** + +**1. Make a POST requests** + +```bash + curl -X "POST" "http://127.0.0.1:8000/add_movie" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json; charset=utf-8' \ + -d '{ + "name": "Whiplash" + }' +``` + +```bash + curl -X "POST" "http://127.0.0.1:8000/add_movie" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json; charset=utf-8' \ + -d '{ + "name": "Chappie" + }' +``` + +```bash + curl -X "POST" "http://127.0.0.1:8000/add_movie" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json; charset=utf-8' \ + -d '{ + "name": "Titanic" + }' +``` + +**2. Make a GET request** + +In order to see all the movies added to the database, run: + +``` +curl -X "GET" "http://127.0.0.1:8000/movies" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json; charset=utf-8' +``` + +**3. Make a DELETE request** + +In order to delete all the movies, run: + +```bash + curl -X "DELETE" "http://127.0.0.1:8000/movies" \ + -H 'Accept: application/json' \ + -H 'Content-Type: application/json; charset=utf-8' +``` + +You will now see a folder named `keploy` with your recorded tests. + +#### Run Tests + +Time to put things to the test 🧪 + +```shell +keploy test -c "python server.py" +``` + +## Wrapping it up 🎉 + +Congrats on the journey so far! You've seen Keploy's power, flexed your coding muscles, and had a bit of fun too! Now, go out there and keep exploring, innovating, and creating! Remember, with the right tools and a sprinkle of fun, anything's possible.😊🚀 + +Happy coding! ✨👩‍💻👨‍💻✨ + +
diff --git a/sanic-mongo/keploy/test-set-0/mocks.yaml b/sanic-mongo/keploy/test-set-0/mocks.yaml new file mode 100644 index 0000000..55e5e0a --- /dev/null +++ b/sanic-mongo/keploy/test-set-0/mocks.yaml @@ -0,0 +1,490 @@ +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-0 +spec: + metadata: + operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo|Motor","version": "4.6.3|3.4.0"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "5.15.146.1-microsoft-standard-WSL2"},"platform": "CPython 3.10.12.final.0|asyncio"}}, returnFieldsSelector: }' + type: config + requests: + - header: + length: 303 + requestId: 1804289383 + responseTo: 0 + Opcode: 2004 + message: + flags: 0 + collection_name: admin.$cmd + number_to_skip: 0 + number_to_return: -1 + query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo|Motor","version":"4.6.3|3.4.0"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"5.15.146.1-microsoft-standard-WSL2"},"platform":"CPython 3.10.12.final.0|asyncio"}}' + return_fields_selector: "" + responses: + - header: + length: 329 + requestId: 13 + responseTo: 1804289383 + Opcode: 1 + message: + response_flags: 8 + cursor_id: 0 + starting_from: 0 + number_returned: 1 + documents: + - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"667b1d2066b0c1d16885b016"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1719344783026"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"4"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' + read_delay: 560917 + created: 1719344783 + reqTimestampMock: 2024-06-26T01:16:23.025984506+05:30 + resTimestampMock: 2024-06-26T01:16:23.026710262+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-1 +spec: + metadata: + operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo|Motor","version": "4.6.3|3.4.0"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "5.15.146.1-microsoft-standard-WSL2"},"platform": "CPython 3.10.12.final.0|asyncio"},"compression": []}, returnFieldsSelector: }' + type: config + requests: + - header: + length: 321 + requestId: 1714636915 + responseTo: 0 + Opcode: 2004 + message: + flags: 0 + collection_name: admin.$cmd + number_to_skip: 0 + number_to_return: -1 + query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo|Motor","version":"4.6.3|3.4.0"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"5.15.146.1-microsoft-standard-WSL2"},"platform":"CPython 3.10.12.final.0|asyncio"},"compression":[]}' + return_fields_selector: "" + responses: + - header: + length: 329 + requestId: 15 + responseTo: 1714636915 + Opcode: 1 + message: + response_flags: 8 + cursor_id: 0 + starting_from: 0 + number_returned: 1 + documents: + - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"667b1d2066b0c1d16885b016"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1719344783030"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"6"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' + read_delay: 657515 + created: 1719344783 + reqTimestampMock: 2024-06-26T01:16:23.030363133+05:30 + resTimestampMock: 2024-06-26T01:16:23.031173194+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-2 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"insert":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }, { SectionSingle identifier: documents , msgs: [ {"_id":"667b1e8fd71cb97567de07c5","name":"Whiplash"} ] }], checksum: 0 }' + requests: + - header: + length: 179 + requestId: 1957747793 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"insert":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + - '{ SectionSingle identifier: documents , msgs: [ {"_id":"667b1e8fd71cb97567de07c5","name":"Whiplash"} ] }' + checksum: 0 + read_delay: 542094 + responses: + - header: + length: 45 + requestId: 16 + responseTo: 1957747793 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 551413 + created: 1719344783 + reqTimestampMock: 2024-06-26T01:16:23.031860881+05:30 + resTimestampMock: 2024-06-26T01:16:23.032549882+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-3 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"movies","filter":{"_id":"667b1e8fd71cb97567de07c5"},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }], checksum: 0 }' + requests: + - header: + length: 166 + requestId: 424238335 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"movies","filter":{"_id":"667b1e8fd71cb97567de07c5"},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + checksum: 0 + read_delay: 1402363 + responses: + - header: + length: 162 + requestId: 17 + responseTo: 424238335 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":"667b1e8fd71cb97567de07c5","name":"Whiplash"}],"id":{"$numberLong":"0"},"ns":"myapp.movies"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 778841 + created: 1719344783 + reqTimestampMock: 2024-06-26T01:16:23.034169772+05:30 + resTimestampMock: 2024-06-26T01:16:23.035109665+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-4 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"insert":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }, { SectionSingle identifier: documents , msgs: [ {"_id":"667b1e95d71cb97567de07c6","name":"Chappie"} ] }], checksum: 0 }' + requests: + - header: + length: 178 + requestId: 719885386 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"insert":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + - '{ SectionSingle identifier: documents , msgs: [ {"_id":"667b1e95d71cb97567de07c6","name":"Chappie"} ] }' + checksum: 0 + read_delay: 6203095487 + responses: + - header: + length: 45 + requestId: 18 + responseTo: 719885386 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 745693 + created: 1719344789 + reqTimestampMock: 2024-06-26T01:16:29.238351946+05:30 + resTimestampMock: 2024-06-26T01:16:29.239303785+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-5 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"movies","filter":{"_id":"667b1e95d71cb97567de07c6"},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }], checksum: 0 }' + requests: + - header: + length: 166 + requestId: 1649760492 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"movies","filter":{"_id":"667b1e95d71cb97567de07c6"},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + checksum: 0 + read_delay: 2447949 + responses: + - header: + length: 161 + requestId: 19 + responseTo: 1649760492 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":"667b1e95d71cb97567de07c6","name":"Chappie"}],"id":{"$numberLong":"0"},"ns":"myapp.movies"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 630241 + created: 1719344789 + reqTimestampMock: 2024-06-26T01:16:29.241914889+05:30 + resTimestampMock: 2024-06-26T01:16:29.242682647+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-6 +spec: + metadata: + operation: '{ OpMsg flags: 65536, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"667b1d2066b0c1d16885b016"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 134 + requestId: 846930886 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 65536 + sections: + - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"667b1d2066b0c1d16885b016"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }' + checksum: 0 + read_delay: 2161277 + responses: + - header: + length: 313 + requestId: 20 + responseTo: 846930886 + Opcode: 2013 + message: + flagBits: 2 + sections: + - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"667b1d2066b0c1d16885b016"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1719344793039"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"4"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 10010918319 + created: 1719344793 + reqTimestampMock: 2024-06-26T01:16:23.029068649+05:30 + resTimestampMock: 2024-06-26T01:16:33.040142118+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-7 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 52 + requestId: 596516649 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }' + checksum: 0 + read_delay: 10012578387 + responses: + - header: + length: 313 + requestId: 21 + responseTo: 596516649 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"667b1d2066b0c1d16885b016"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1719344793043"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"5"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 455336 + created: 1719344793 + reqTimestampMock: 2024-06-26T01:16:33.043665579+05:30 + resTimestampMock: 2024-06-26T01:16:33.044280965+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-8 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"insert":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }, { SectionSingle identifier: documents , msgs: [ {"_id":"667b1e9bd71cb97567de07c7","name":"Titanic"} ] }], checksum: 0 }' + requests: + - header: + length: 178 + requestId: 1189641421 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"insert":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + - '{ SectionSingle identifier: documents , msgs: [ {"_id":"667b1e9bd71cb97567de07c7","name":"Titanic"} ] }' + checksum: 0 + read_delay: 6649200875 + responses: + - header: + length: 45 + requestId: 22 + responseTo: 1189641421 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 561569 + created: 1719344795 + reqTimestampMock: 2024-06-26T01:16:35.892029796+05:30 + resTimestampMock: 2024-06-26T01:16:35.892711+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-9 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"movies","filter":{"_id":"667b1e9bd71cb97567de07c7"},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }], checksum: 0 }' + requests: + - header: + length: 166 + requestId: 1025202362 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"movies","filter":{"_id":"667b1e9bd71cb97567de07c7"},"limit":{"$numberInt":"1"},"singleBatch":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + checksum: 0 + read_delay: 1988209 + responses: + - header: + length: 161 + requestId: 23 + responseTo: 1025202362 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":"667b1e9bd71cb97567de07c7","name":"Titanic"}],"id":{"$numberLong":"0"},"ns":"myapp.movies"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 502216 + created: 1719344795 + reqTimestampMock: 2024-06-26T01:16:35.894867685+05:30 + resTimestampMock: 2024-06-26T01:16:35.895517417+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-10 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"movies","filter":{},"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }], checksum: 0 }' + requests: + - header: + length: 107 + requestId: 1350490027 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"movies","filter":{},"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + checksum: 0 + read_delay: 6177066246 + responses: + - header: + length: 343 + requestId: 24 + responseTo: 1350490027 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":"667b1e6d33a7849da6520cea","name":"Whiplash"},{"_id":"667b1e8fd71cb97567de07c5","name":"Whiplash"},{"_id":"667b1e95d71cb97567de07c6","name":"Chappie"},{"_id":"667b1e9bd71cb97567de07c7","name":"Titanic"}],"id":{"$numberLong":"0"},"ns":"myapp.movies"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 1275690 + created: 1719344802 + reqTimestampMock: 2024-06-26T01:16:42.072696856+05:30 + resTimestampMock: 2024-06-26T01:16:42.074091198+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-11 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 65 + requestId: 783368690 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }' + checksum: 0 + read_delay: 10012605933 + responses: + - header: + length: 314 + requestId: 26 + responseTo: 783368690 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"667b1d2066b0c1d16885b016"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1719344803057"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"5"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"21"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 522723 + created: 1719344803 + reqTimestampMock: 2024-06-26T01:16:43.057053931+05:30 + resTimestampMock: 2024-06-26T01:16:43.057762251+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-12 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"delete":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }, { SectionSingle identifier: deletes , msgs: [ {"q":{},"limit":{"$numberInt":"0"}} ] }], checksum: 0 }' + requests: + - header: + length: 143 + requestId: 1102520059 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"delete":"movies","ordered":true,"lsid":{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}},"$db":"myapp"} }' + - '{ SectionSingle identifier: deletes , msgs: [ {"q":{},"limit":{"$numberInt":"0"}} ] }' + checksum: 0 + read_delay: 9127441948 + responses: + - header: + length: 45 + requestId: 27 + responseTo: 1102520059 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"4"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 761264 + created: 1719344811 + reqTimestampMock: 2024-06-26T01:16:51.201703124+05:30 + resTimestampMock: 2024-06-26T01:16:51.20258821+05:30 +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-13 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"endSessions":[{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}}],"$db":"admin"} }], checksum: 0 }' + requests: + - header: + length: 92 + requestId: 1967513926 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"endSessions":[{"id":{"$binary":{"base64":"Mx+ps9bVQSSsAdH3K5VdCg==","subType":"04"}}}],"$db":"admin"} }' + checksum: 0 + read_delay: 8507808445 + responses: + - header: + length: 38 + requestId: 30 + responseTo: 1967513926 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 382255 + created: 1719344819 + reqTimestampMock: 2024-06-26T01:16:59.710542397+05:30 + resTimestampMock: 2024-06-26T01:16:59.711041681+05:30 diff --git a/sanic-mongo/keploy/test-set-0/tests/test-1.yaml b/sanic-mongo/keploy/test-set-0/tests/test-1.yaml new file mode 100644 index 0000000..320cd9b --- /dev/null +++ b/sanic-mongo/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,42 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/add_movie + header: + Accept: application/json + Content-Length: "20" + Content-Type: application/json; charset=utf-8 + Host: 127.0.0.1:8000 + User-Agent: curl/7.81.0 + body: '{"name": "Whiplash"}' + timestamp: 2024-06-26T01:16:23.022752322+05:30 + resp: + status_code: 200 + header: + Alt-Svc: "" + Connection: keep-alive + Content-Length: "52" + Content-Type: application/json + body: '{"_id":"667b1e8fd71cb97567de07c5","name":"Whiplash"}' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-06-26T01:16:25.086349854+05:30 + objects: [] + assertions: + noise: {} + created: 1719344785 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/add_movie \ + --header 'Host: 127.0.0.1:8000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data '{"name": "Whiplash"}' diff --git a/sanic-mongo/keploy/test-set-0/tests/test-2.yaml b/sanic-mongo/keploy/test-set-0/tests/test-2.yaml new file mode 100644 index 0000000..719b20c --- /dev/null +++ b/sanic-mongo/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,42 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/add_movie + header: + Accept: application/json + Content-Length: "19" + Content-Type: application/json; charset=utf-8 + Host: 127.0.0.1:8000 + User-Agent: curl/7.81.0 + body: '{"name": "Chappie"}' + timestamp: 2024-06-26T01:16:29.236765225+05:30 + resp: + status_code: 200 + header: + Alt-Svc: "" + Connection: keep-alive + Content-Length: "51" + Content-Type: application/json + body: '{"_id":"667b1e95d71cb97567de07c6","name":"Chappie"}' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-06-26T01:16:31.312393895+05:30 + objects: [] + assertions: + noise: {} + created: 1719344791 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/add_movie \ + --header 'Host: 127.0.0.1:8000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --data '{"name": "Chappie"}' diff --git a/sanic-mongo/keploy/test-set-0/tests/test-3.yaml b/sanic-mongo/keploy/test-set-0/tests/test-3.yaml new file mode 100644 index 0000000..9948d84 --- /dev/null +++ b/sanic-mongo/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,42 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/add_movie + header: + Accept: application/json + Content-Length: "19" + Content-Type: application/json; charset=utf-8 + Host: 127.0.0.1:8000 + User-Agent: curl/7.81.0 + body: '{"name": "Titanic"}' + timestamp: 2024-06-26T01:16:35.890538161+05:30 + resp: + status_code: 200 + header: + Alt-Svc: "" + Connection: keep-alive + Content-Length: "51" + Content-Type: application/json + body: '{"_id":"667b1e9bd71cb97567de07c7","name":"Titanic"}' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-06-26T01:16:37.940966466+05:30 + objects: [] + assertions: + noise: {} + created: 1719344797 +curl: |- + curl --request POST \ + --url http://127.0.0.1:8000/add_movie \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json; charset=utf-8' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'User-Agent: curl/7.81.0' \ + --data '{"name": "Titanic"}' diff --git a/sanic-mongo/keploy/test-set-0/tests/test-4.yaml b/sanic-mongo/keploy/test-set-0/tests/test-4.yaml new file mode 100644 index 0000000..f69d270 --- /dev/null +++ b/sanic-mongo/keploy/test-set-0/tests/test-4.yaml @@ -0,0 +1,40 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-4 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/movies + header: + Accept: application/json + Content-Type: application/json; charset=utf-8 + Host: 127.0.0.1:8000 + User-Agent: curl/7.81.0 + body: "" + timestamp: 2024-06-26T01:16:42.071382334+05:30 + resp: + status_code: 200 + header: + Alt-Svc: "" + Connection: keep-alive + Content-Length: "211" + Content-Type: application/json + body: '[{"_id":"667b1e6d33a7849da6520cea","name":"Whiplash"},{"_id":"667b1e8fd71cb97567de07c5","name":"Whiplash"},{"_id":"667b1e95d71cb97567de07c6","name":"Chappie"},{"_id":"667b1e9bd71cb97567de07c7","name":"Titanic"}]' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-06-26T01:16:44.167252247+05:30 + objects: [] + assertions: + noise: {} + created: 1719344804 +curl: | + curl --request GET \ + --url http://127.0.0.1:8000/movies \ + --header 'Host: 127.0.0.1:8000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: application/json' \ + --header 'Content-Type: application/json; charset=utf-8' \ diff --git a/sanic-mongo/keploy/test-set-0/tests/test-5.yaml b/sanic-mongo/keploy/test-set-0/tests/test-5.yaml new file mode 100644 index 0000000..198d464 --- /dev/null +++ b/sanic-mongo/keploy/test-set-0/tests/test-5.yaml @@ -0,0 +1,38 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-5 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://127.0.0.1:8000/movies + header: + Accept: application/json + Content-Type: application/json; charset=utf-8 + Host: 127.0.0.1:8000 + User-Agent: curl/7.81.0 + body: "" + timestamp: 2024-06-26T01:16:51.200010582+05:30 + resp: + status_code: 204 + header: + Alt-Svc: "" + Connection: keep-alive + body: "" + status_message: No Content + proto_major: 0 + proto_minor: 0 + timestamp: 2024-06-26T01:16:53.208616296+05:30 + objects: [] + assertions: + noise: {} + created: 1719344813 +curl: | + curl --request DELETE \ + --url http://127.0.0.1:8000/movies \ + --header 'Content-Type: application/json; charset=utf-8' \ + --header 'Host: 127.0.0.1:8000' \ + --header 'User-Agent: curl/7.81.0' \ + --header 'Accept: application/json' \ diff --git a/sanic-mongo/requirements.txt b/sanic-mongo/requirements.txt new file mode 100644 index 0000000..04a5484 --- /dev/null +++ b/sanic-mongo/requirements.txt @@ -0,0 +1,3 @@ +pymongo==4.6.3 +sanic==23.12.1 +sanic_motor==0.7.0 \ No newline at end of file diff --git a/sanic-mongo/server.py b/sanic-mongo/server.py new file mode 100644 index 0000000..c05998d --- /dev/null +++ b/sanic-mongo/server.py @@ -0,0 +1,60 @@ +from sanic import Sanic, text +from sanic.response import json as json_response +from sanic.exceptions import NotFound +from sanic_motor import BaseModel +from bson import ObjectId + +app = Sanic(__name__) + +settings = dict( + MOTOR_URI='mongodb://localhost:27017/myapp', LOGO=None +) + +app.config.update(settings) + +BaseModel.init_app(app) + +class Movie(BaseModel): + __coll__ = "movies" + +@app.route("/add_movie", methods=["POST"]) +async def add_movie(request): + movie = request.json + movie["_id"] = str(ObjectId()) + + new_movie = await Movie.insert_one(movie) + created_movie = await Movie.find_one({"_id": new_movie.inserted_id}, as_raw=True) + return json_response(created_movie) + + +@app.route("/movies", methods=["GET"]) +async def list_movies(request): + movies = await Movie.find(as_raw=True) + return json_response(movies.objects) + + + +@app.route("/movies/", methods=["GET"]) +async def get_movie(request, id): + if (movies := await Movie.find_one({"_id": id}, as_raw=True)) is not None: + return json_response(movies) + + raise NotFound(f"Movie {id} not found") + + +@app.route("/movies/", methods=["DELETE"]) +async def delete_movie(request, id): + delete_result = await Movie.delete_one({"_id": id}) + + if delete_result.deleted_count == 1: + return json_response({}, status=204) + + raise NotFound(f"Movie {id} not found") + +@app.route("/movies", methods=["DELETE"]) +async def delete_all_movies(request): + await Movie.delete_many({}) + return json_response({}, status=204) + +if __name__ == "__main__": + app.run(host="127.0.0.1", port=8000, debug=True) \ No newline at end of file From 442f9e2a54a9681e87cfa5ff35577329a6e79bb4 Mon Sep 17 00:00:00 2001 From: Aman Rai <98376634+Aman172003@users.noreply.github.com> Date: Thu, 8 Aug 2024 12:08:40 +0530 Subject: [PATCH 20/31] feat: created a sample app using flask and redis (#26) * feat: Created a sample app using flask and redis Signed-off-by: Aman172003 * removed errors Signed-off-by: Aman172003 --------- Signed-off-by: Aman172003 --- README.md | 2 + flask-redis/Dockerfile | 26 + flask-redis/README.md | 160 +++++ flask-redis/api.txt | 44 ++ flask-redis/app.py | 14 + flask-redis/docker-compose.yml | 36 ++ flask-redis/dump.rdb | Bin 0 -> 201 bytes flask-redis/keploy.yml | 43 ++ .../reports/test-run-0/test-set-0-report.yaml | 606 ++++++++++++++++++ flask-redis/keploy/test-set-0/mocks.yaml | 417 ++++++++++++ .../keploy/test-set-0/tests/test-1.yaml | 47 ++ .../keploy/test-set-0/tests/test-2.yaml | 50 ++ .../keploy/test-set-0/tests/test-3.yaml | 43 ++ .../keploy/test-set-0/tests/test-4.yaml | 49 ++ .../keploy/test-set-0/tests/test-5.yaml | 50 ++ .../keploy/test-set-0/tests/test-6.yaml | 42 ++ flask-redis/redisClient.py | 12 + flask-redis/requirements.txt | 3 + flask-redis/routes/book_routes.py | 133 ++++ 19 files changed, 1777 insertions(+) create mode 100644 flask-redis/Dockerfile create mode 100644 flask-redis/README.md create mode 100644 flask-redis/api.txt create mode 100644 flask-redis/app.py create mode 100644 flask-redis/docker-compose.yml create mode 100644 flask-redis/dump.rdb create mode 100755 flask-redis/keploy.yml create mode 100755 flask-redis/keploy/reports/test-run-0/test-set-0-report.yaml create mode 100755 flask-redis/keploy/test-set-0/mocks.yaml create mode 100755 flask-redis/keploy/test-set-0/tests/test-1.yaml create mode 100755 flask-redis/keploy/test-set-0/tests/test-2.yaml create mode 100755 flask-redis/keploy/test-set-0/tests/test-3.yaml create mode 100755 flask-redis/keploy/test-set-0/tests/test-4.yaml create mode 100755 flask-redis/keploy/test-set-0/tests/test-5.yaml create mode 100755 flask-redis/keploy/test-set-0/tests/test-6.yaml create mode 100644 flask-redis/redisClient.py create mode 100644 flask-redis/requirements.txt create mode 100644 flask-redis/routes/book_routes.py diff --git a/README.md b/README.md index 9e475d0..55de833 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,8 @@ This repo contains the samples for [Keploy's](https://keploy.io) integration wit 4. [FastAPI-Twilio](https://github.com/keploy/samples-python/tree/main/fastapi-twilio) - This application is a SMS sending API built using Python's FastAPI and Twilio for their SMS sharing service. +5. [Flask-Redis](https://github.com/keploy/samples-python/tree/main/flask-redis) - This Flask-based application provides a book management system utilizing Redis for caching and storage. It supports adding, retrieving, updating, and deleting book records, with optimized search functionality and cache management for improved performance. The API endpoints ensure efficient data handling and quick access to book information. + ## Community Support ❤️ ### 🤔 Questions? diff --git a/flask-redis/Dockerfile b/flask-redis/Dockerfile new file mode 100644 index 0000000..9c0e897 --- /dev/null +++ b/flask-redis/Dockerfile @@ -0,0 +1,26 @@ +# Use the official Python image from the Docker Hub +FROM python:3.10-slim + +# RUN apt-get update && apt-get install -y curl +# Set the working directory in the container +WORKDIR /app + +# Copy the requirements file into the container +COPY requirements.txt . + +# Install the Python dependencies +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the rest of the application code into the container +COPY . . + +# Download Keploy CA certificate and setup script +# RUN curl -o ca.crt https://raw.githubusercontent.com/keploy/keploy/main/pkg/core/proxy/asset/ca.crt && \ +# curl -o setup_ca.sh https://raw.githubusercontent.com/keploy/keploy/main/pkg/core/proxy/asset/setup_ca.sh && \ +# chmod +x setup_ca.sh # Make the setup script executable + +# Expose the port the app runs on +EXPOSE 5000 + +# Define the command to run the app +CMD ["python", "app.py"] diff --git a/flask-redis/README.md b/flask-redis/README.md new file mode 100644 index 0000000..7364e9d --- /dev/null +++ b/flask-redis/README.md @@ -0,0 +1,160 @@ +# flask-redis + +A sample App using flask and redis + +## Setup application + +1. Clone the repository and move to flask-redis folder +2. Create a .env file and copy-paste below credentials: + +```bash +REDIS_HOST=redis +REDIS_PORT=6379 +``` + +# Installing Redis + +```sh +brew install redis +``` +If homebrew is not installed, then go to https://brew.sh/ and install it. + +```bash +git clone https://github.com/keploy/samples-typescript && cd samples-typescript/flask-redis + +# Install the dependencies +pip3 install -r requirements.txt +``` + +# Installing Keploy + +Let's get started by setting up the Keploy alias with this command: + +```sh +curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh +``` + +## Using Keploy : + +There are 2 ways you can run this sample application. + +1. [Natively on Linux/WSL](#natively-on-ubuntuwsl) +2. [Using Docker](#running-sample-app-using-docker) + +# Natively on Ubuntu/WSL + +## Let's install certificates + +1. **Install required packages:** + + ```sh + sudo apt-get install -y --no-install-recommends ca-certificates curl + ``` + + This command installs necessary packages without additional recommended packages. + +2. **Download CA certificate:** + + ```sh + curl -o ca.crt https://raw.githubusercontent.com/keploy/keploy/main/pkg/core/proxy/asset/ca.crt + ``` + + This command downloads the CA certificate to `ca.crt`. + +3. **Download setup script:** + + ```sh + curl -o setup_ca.sh https://raw.githubusercontent.com/keploy/keploy/main/pkg/core/proxy/asset/setup_ca.sh + ``` + + This command downloads the setup script to `setup_ca.sh`. + +4. **Make the setup script executable:** + + ```sh + chmod +x setup_ca.sh + ``` + + This command changes the permissions of `setup_ca.sh` to make it executable. + +5. **Run the setup script:** + + ```sh + source ./setup_ca.sh + ``` + + This command executes the setup script in the current shell. + +6. **Start the redis server:** + ```sh + redis-server + ``` + This command starts the redis server. + +## Capture the test cases + +1. **Start recording tests:** + ```bash + sudo -E env "PATH=$PATH" keploybin record -c 'python3 app.py' + ``` + +## Let's Generate the test cases + +Make API Calls using Hoppscotch, Postman or cURL command. Keploy will capture those calls to generate test suites containing test cases and data mocks. + +1. Refer to flask-redis/api.txt to make api calls. + +2. **Observe terminal output:** + Let's go ahead and create a few more test cases for different endpoints! + +## Running the test cases + +1. **Start the application:** + + ```bash + python3 app.py + ``` + +2. **Run the recorded tests:** + + ```bash + sudo -E env "PATH=$PATH" keploybin test -c 'python3 app.py' --delay 10 + ``` + +3. **Observe test run results:** + _Voila!! Our test cases have passed 🌟_ + +--- + +# Using Docker + +Since we have to setup our app using docker(make sure your docker is running) + +## Create a custom network for Keploy since we are using the Docker + +```bash +docker network create keploy-network +``` + +## Capture the testcases + +We will run the keploy in record mode with docker-compose to start our application:- + +```bash +keploy record -c "sudo docker-compose up" --containerName "flask-web" + +``` + +#### Let's generate the testcases. + +Make API Calls using [Hoppscotch](https://hoppscotch.io), [Postman](https://postman.com) or curl command. Keploy with capture those calls to generate the test-suites containing testcases and data mocks. + +1. Refer to flask-redis/api.txt to make api calls + +## Running the testcases + +```bash +keploy test -c 'sudo docker-compose up' --containerName "flask-web" --delay 10 +``` + +_Voila!! Our testcases has passed 🌟_ diff --git a/flask-redis/api.txt b/flask-redis/api.txt new file mode 100644 index 0000000..68b4b23 --- /dev/null +++ b/flask-redis/api.txt @@ -0,0 +1,44 @@ +--------------------------------------------------------------------------------------------------- +// Add a Book + +curl -X POST http://localhost:5000/books/ \ +-H "Content-Type: application/json" \ +-d '{"title": "1984", "author": "George Orwell"}' + +--------------------------------------------------------------------------------------------------- + +// Get All Books(with Pagination) + +curl -X GET "http://localhost:5000/books/?page=1&limit=10" + +--------------------------------------------------------------------------------------------------- + +// Get Book Details + +curl -X GET http://localhost:5000/books/1 + +--------------------------------------------------------------------------------------------------- + + +//Search Books by Title + +curl -X GET "http://localhost:5000/books/search?query=1984" + + +--------------------------------------------------------------------------------------------------- + +//Update a Book + +curl -X PUT http://localhost:5000/books/1 \ +-H "Content-Type: application/json" \ +-d '{"title": "1984 - Updated", "author": "George Orwell"}' + + +--------------------------------------------------------------------------------------------------- + +//Delete a Book + +curl -X DELETE http://localhost:5000/books/1 + +--------------------------------------------------------------------------------------------------- + diff --git a/flask-redis/app.py b/flask-redis/app.py new file mode 100644 index 0000000..bf701d1 --- /dev/null +++ b/flask-redis/app.py @@ -0,0 +1,14 @@ +from flask import Flask +from routes.book_routes import book + +app = Flask(__name__) + +# Register Blueprints +app.register_blueprint(book, url_prefix="/books") + +@app.route('/', methods=['GET']) +def hello(): + return {"message": "Welcome to the Book Management System!"}, 200 + +if __name__ == '__main__': + app.run(host='0.0.0.0', port=5000, debug=True) diff --git a/flask-redis/docker-compose.yml b/flask-redis/docker-compose.yml new file mode 100644 index 0000000..99a6016 --- /dev/null +++ b/flask-redis/docker-compose.yml @@ -0,0 +1,36 @@ +version: "3.8" + +services: + web: + build: . + container_name: flask-web + restart: always + ports: + - "5000:5000" + depends_on: + - redis + environment: + - FLASK_ENV=development + - REDIS_HOST=redis + - REDIS_PORT=6379 + # volumes: + # - .:/usr/src/app + networks: + - keploy-network + + redis: + image: "redis:alpine" + container_name: redis-server + restart: always + ports: + - "6379:6379" + # volumes: + # - db_data:/var/lib/redis + networks: + - keploy-network + +networks: + keploy-network: + external: true +# volumes: +# db_data: diff --git a/flask-redis/dump.rdb b/flask-redis/dump.rdb new file mode 100644 index 0000000000000000000000000000000000000000..601ee4a561fc10586965dc672a2012bd01d975ca GIT binary patch literal 201 zcmWG?b@2=~FfcUy#aWb^l3A=^hTqJL46M18*{PMh9;rDw`8o%TJ~=TtBh{)PF+DZjR4=+(sU))`CsoNxLCMh4!bC|&K`F7c sBqP5FB;uZ$UzDDz;9pb@G*PKGmVq5)M0{q-0oMPb9b0d1@c6qL0O<=!bpQYW literal 0 HcmV?d00001 diff --git a/flask-redis/keploy.yml b/flask-redis/keploy.yml new file mode 100755 index 0000000..7b17386 --- /dev/null +++ b/flask-redis/keploy.yml @@ -0,0 +1,43 @@ +path: "" +appId: 0 +appName: "" +command: sudo docker-compose up +port: 0 +dnsPort: 26789 +proxyPort: 16789 +debug: false +disableTele: false +disableANSI: false +containerName: flask-web +networkName: "" +buildDelay: 30 +test: + selectedTests: {} + globalNoise: + global: {} + test-sets: {} + delay: 5 + apiTimeout: 5 + skipCoverage: false + coverageReportPath: "" + ignoreOrdering: true + mongoPassword: default@123 + language: "" + removeUnusedMocks: false + fallBackOnMiss: false + jacocoAgentPath: "" + basePath: "" + mocking: true + ignoredTests: {} +record: + filters: [] + recordTimer: 0s +configPath: "" +bypassRules: [] +generateGithubActions: false +keployContainer: keploy-v2 +keployNetwork: keploy-network +cmdType: native +inCi: false + +# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file. diff --git a/flask-redis/keploy/reports/test-run-0/test-set-0-report.yaml b/flask-redis/keploy/reports/test-run-0/test-set-0-report.yaml new file mode 100755 index 0000000..34f4af7 --- /dev/null +++ b/flask-redis/keploy/reports/test-run-0/test-set-0-report.yaml @@ -0,0 +1,606 @@ +version: api.keploy.io/v1beta1 +name: test-set-0-report +status: PASSED +success: 6 +failure: 0 +ignored: 0 +total: 6 +tests: + - kind: Http + name: test-set-0 + status: PASSED + started: 1722636974 + completed: 1722636974 + test_case_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0 + mock_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0/mocks + test_case_id: test-1 + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://172.18.0.4:5000/books/ + header: + Accept: '*/*' + Content-Length: "44" + Content-Type: application/json + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: '{"title": "1984", "author": "George Orwell"}' + timestamp: 2024-08-02T22:15:10.596402605Z + resp: + status_code: 201 + header: + Content-Length: "59" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:16:14 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "book_id": 1, + "message": "Book added successfully" + } + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 201 + actual: 201 + headers_result: + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + actual: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + - normal: true + expected: + key: Content-Length + value: + - "59" + actual: + key: Content-Length + value: + - "59" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Fri, 02 Aug 2024 22:15:10 GMT + actual: + key: Date + value: + - Fri, 02 Aug 2024 22:16:14 GMT + body_result: + - normal: true + type: JSON + expected: | + { + "book_id": 1, + "message": "Book added successfully" + } + actual: | + { + "book_id": 1, + "message": "Book added successfully" + } + dep_result: [] + - kind: Http + name: test-set-0 + status: PASSED + started: 1722636974 + completed: 1722636974 + test_case_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0 + mock_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0/mocks + test_case_id: test-2 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://172.18.0.4:5000/books/?page=1&limit=10 + url_params: + limit: "10" + page: "1" + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:17.339856691Z + resp: + status_code: 200 + header: + Content-Length: "88" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:16:14 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "books": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Fri, 02 Aug 2024 22:15:17 GMT + actual: + key: Date + value: + - Fri, 02 Aug 2024 22:16:14 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + actual: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + - normal: true + expected: + key: Content-Length + value: + - "88" + actual: + key: Content-Length + value: + - "88" + body_result: + - normal: true + type: JSON + expected: | + { + "books": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + actual: | + { + "books": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + dep_result: [] + - kind: Http + name: test-set-0 + status: PASSED + started: 1722636974 + completed: 1722636974 + test_case_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0 + mock_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0/mocks + test_case_id: test-3 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://172.18.0.4:5000/books/1 + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:24.919087736Z + resp: + status_code: 200 + header: + Content-Length: "51" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:16:14 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "author": "George Orwell", + "title": "1984" + } + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Date + value: + - Fri, 02 Aug 2024 22:15:24 GMT + actual: + key: Date + value: + - Fri, 02 Aug 2024 22:16:14 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + actual: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + - normal: true + expected: + key: Content-Length + value: + - "51" + actual: + key: Content-Length + value: + - "51" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + body_result: + - normal: true + type: JSON + expected: | + { + "author": "George Orwell", + "title": "1984" + } + actual: | + { + "author": "George Orwell", + "title": "1984" + } + dep_result: [] + - kind: Http + name: test-set-0 + status: PASSED + started: 1722636974 + completed: 1722636974 + test_case_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0 + mock_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0/mocks + test_case_id: test-4 + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://172.18.0.4:5000/books/search?query=1984 + url_params: + query: "1984" + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:32.960447823Z + resp: + status_code: 200 + header: + Content-Length: "90" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:16:14 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "results": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Length + value: + - "90" + actual: + key: Content-Length + value: + - "90" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Fri, 02 Aug 2024 22:15:32 GMT + actual: + key: Date + value: + - Fri, 02 Aug 2024 22:16:14 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + actual: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + body_result: + - normal: true + type: JSON + expected: | + { + "results": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + actual: | + { + "results": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + dep_result: [] + - kind: Http + name: test-set-0 + status: PASSED + started: 1722636974 + completed: 1722636974 + test_case_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0 + mock_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0/mocks + test_case_id: test-5 + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://172.18.0.4:5000/books/1 + header: + Accept: '*/*' + Content-Length: "54" + Content-Type: application/json + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: '{"title": "1984 - Updated", "author": "George Orwell"}' + timestamp: 2024-08-02T22:15:39.802018618Z + resp: + status_code: 200 + header: + Content-Length: "123" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:16:14 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "book": { + "author": "George Orwell", + "title": "1984 - Updated" + }, + "message": "Book updated successfully" + } + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Date + value: + - Fri, 02 Aug 2024 22:15:39 GMT + actual: + key: Date + value: + - Fri, 02 Aug 2024 22:16:14 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + actual: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + - normal: true + expected: + key: Content-Length + value: + - "123" + actual: + key: Content-Length + value: + - "123" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + body_result: + - normal: true + type: JSON + expected: | + { + "book": { + "author": "George Orwell", + "title": "1984 - Updated" + }, + "message": "Book updated successfully" + } + actual: | + { + "book": { + "author": "George Orwell", + "title": "1984 - Updated" + }, + "message": "Book updated successfully" + } + dep_result: [] + - kind: Http + name: test-set-0 + status: PASSED + started: 1722636974 + completed: 1722636974 + test_case_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0 + mock_path: /Users/amanrai/Desktop/flask-redis/keploy/test-set-0/mocks + test_case_id: test-6 + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://172.18.0.4:5000/books/1 + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:47.228393997Z + resp: + status_code: 200 + header: + Content-Length: "45" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:16:14 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "message": "Book deleted successfully" + } + status_message: "" + proto_major: 0 + proto_minor: 0 + timestamp: 0001-01-01T00:00:00Z + noise: + header.Date: [] + result: + status_code: + normal: true + expected: 200 + actual: 200 + headers_result: + - normal: true + expected: + key: Content-Length + value: + - "45" + actual: + key: Content-Length + value: + - "45" + - normal: true + expected: + key: Content-Type + value: + - application/json + actual: + key: Content-Type + value: + - application/json + - normal: true + expected: + key: Date + value: + - Fri, 02 Aug 2024 22:15:47 GMT + actual: + key: Date + value: + - Fri, 02 Aug 2024 22:16:14 GMT + - normal: true + expected: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + actual: + key: Server + value: + - Werkzeug/3.0.3 Python/3.10.14 + body_result: + - normal: true + type: JSON + expected: | + { + "message": "Book deleted successfully" + } + actual: | + { + "message": "Book deleted successfully" + } + dep_result: [] +test_set: test-set-0 diff --git a/flask-redis/keploy/test-set-0/mocks.yaml b/flask-redis/keploy/test-set-0/mocks.yaml new file mode 100755 index 0000000..1e3ba8b --- /dev/null +++ b/flask-redis/keploy/test-set-0/mocks.yaml @@ -0,0 +1,417 @@ +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-0 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*4\r\n$6\r\nCLIENT\r\n$7\r\nSETINFO\r\n$8\r\nLIB-NAME\r\n$8\r\nredis-py\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "+OK\r\n" + reqtimestampmock: 2024-08-02T22:15:10.6084523Z + restimestampmock: 2024-08-02T22:15:10.608930466Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-1 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*4\r\n$6\r\nCLIENT\r\n$7\r\nSETINFO\r\n$7\r\nLIB-VER\r\n$5\r\n5.0.8\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "+OK\r\n" + reqtimestampmock: 2024-08-02T22:15:10.610066633Z + restimestampmock: 2024-08-02T22:15:10.610752633Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-2 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*3\r\n$6\r\nINCRBY\r\n$7\r\nbook_id\r\n$1\r\n1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":1\r\n" + reqtimestampmock: 2024-08-02T22:15:10.611978716Z + restimestampmock: 2024-08-02T22:15:10.612786841Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-3 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*6\r\n$4\r\nHSET\r\n$6\r\nbook:1\r\n$5\r\ntitle\r\n$4\r\n1984\r\n$6\r\nauthor\r\n$13\r\nGeorge Orwell\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":2\r\n" + reqtimestampmock: 2024-08-02T22:15:10.613938591Z + restimestampmock: 2024-08-02T22:15:10.614915925Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-4 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$3\r\nGET\r\n$18\r\nbooks_cache:page_1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "$-1\r\n" + reqtimestampmock: 2024-08-02T22:15:17.343482553Z + restimestampmock: 2024-08-02T22:15:17.344991261Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-5 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$4\r\nKEYS\r\n$6\r\nbook:*\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "*1\r\n$6\r\nbook:1\r\n" + reqtimestampmock: 2024-08-02T22:15:17.345461178Z + restimestampmock: 2024-08-02T22:15:17.346119386Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-6 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$7\r\nHGETALL\r\n$6\r\nbook:1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "*4\r\n$5\r\ntitle\r\n$4\r\n1984\r\n$6\r\nauthor\r\n$13\r\nGeorge Orwell\r\n" + reqtimestampmock: 2024-08-02T22:15:17.346484636Z + restimestampmock: 2024-08-02T22:15:17.346881469Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-7 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*4\r\n$5\r\nSETEX\r\n$18\r\nbooks_cache:page_1\r\n$3\r\n300\r\n$46\r\n[{\"title\": \"1984\", \"author\": \"George Orwell\"}]\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "+OK\r\n" + reqtimestampmock: 2024-08-02T22:15:17.347539428Z + restimestampmock: 2024-08-02T22:15:17.348107886Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-8 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$7\r\nHGETALL\r\n$6\r\nbook:1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "*4\r\n$5\r\ntitle\r\n$4\r\n1984\r\n$6\r\nauthor\r\n$13\r\nGeorge Orwell\r\n" + reqtimestampmock: 2024-08-02T22:15:24.91868625Z + restimestampmock: 2024-08-02T22:15:24.918989625Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-9 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$3\r\nGET\r\n$17\r\nsearch:books:1984\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "$-1\r\n" + reqtimestampmock: 2024-08-02T22:15:32.959388379Z + restimestampmock: 2024-08-02T22:15:32.959604088Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-10 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$4\r\nKEYS\r\n$6\r\nbook:*\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "*1\r\n$6\r\nbook:1\r\n" + reqtimestampmock: 2024-08-02T22:15:32.959842713Z + restimestampmock: 2024-08-02T22:15:32.959998921Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-11 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$7\r\nHGETALL\r\n$6\r\nbook:1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "*4\r\n$5\r\ntitle\r\n$4\r\n1984\r\n$6\r\nauthor\r\n$13\r\nGeorge Orwell\r\n" + reqtimestampmock: 2024-08-02T22:15:32.960231671Z + restimestampmock: 2024-08-02T22:15:32.960389213Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-12 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*4\r\n$5\r\nSETEX\r\n$17\r\nsearch:books:1984\r\n$3\r\n300\r\n$46\r\n[{\"title\": \"1984\", \"author\": \"George Orwell\"}]\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "+OK\r\n" + reqtimestampmock: 2024-08-02T22:15:32.960706004Z + restimestampmock: 2024-08-02T22:15:32.960838838Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-13 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$6\r\nEXISTS\r\n$6\r\nbook:1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":1\r\n" + reqtimestampmock: 2024-08-02T22:15:39.801969841Z + restimestampmock: 2024-08-02T22:15:39.802299174Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-14 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*4\r\n$4\r\nHSET\r\n$6\r\nbook:1\r\n$5\r\ntitle\r\n$14\r\n1984 - Updated\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":0\r\n" + reqtimestampmock: 2024-08-02T22:15:39.802669008Z + restimestampmock: 2024-08-02T22:15:39.803126174Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-15 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*4\r\n$4\r\nHSET\r\n$6\r\nbook:1\r\n$6\r\nauthor\r\n$13\r\nGeorge Orwell\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":0\r\n" + reqtimestampmock: 2024-08-02T22:15:39.803492508Z + restimestampmock: 2024-08-02T22:15:39.803768216Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-16 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*3\r\n$4\r\nHGET\r\n$6\r\nbook:1\r\n$5\r\ntitle\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "$14\r\n1984 - Updated\r\n" + reqtimestampmock: 2024-08-02T22:15:39.804229258Z + restimestampmock: 2024-08-02T22:15:39.804523466Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-17 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*3\r\n$4\r\nHGET\r\n$6\r\nbook:1\r\n$6\r\nauthor\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "$13\r\nGeorge Orwell\r\n" + reqtimestampmock: 2024-08-02T22:15:39.805022091Z + restimestampmock: 2024-08-02T22:15:39.805174924Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-18 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*6\r\n$5\r\nHMSET\r\n$6\r\nbook:1\r\n$5\r\ntitle\r\n$14\r\n1984 - Updated\r\n$6\r\nauthor\r\n$13\r\nGeorge Orwell\r\n" + redisresponses: + - origin: server + message: + - type: string + data: "+OK\r\n" + reqtimestampmock: 2024-08-02T22:15:39.806458299Z + restimestampmock: 2024-08-02T22:15:39.807372758Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-19 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$6\r\nEXISTS\r\n$6\r\nbook:1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":1\r\n" + reqtimestampmock: 2024-08-02T22:15:47.227235428Z + restimestampmock: 2024-08-02T22:15:47.227446803Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-20 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$3\r\nDEL\r\n$6\r\nbook:1\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":1\r\n" + reqtimestampmock: 2024-08-02T22:15:47.227812303Z + restimestampmock: 2024-08-02T22:15:47.228129511Z +--- +version: api.keploy.io/v1beta1 +kind: Redis +name: mock-21 +spec: + metadata: + type: config + redisrequests: + - origin: client + message: + - type: string + data: "*2\r\n$3\r\nDEL\r\n$18\r\nbooks_cache:page_*\r\n" + redisresponses: + - origin: server + message: + - type: string + data: ":0\r\n" + reqtimestampmock: 2024-08-02T22:15:47.228357053Z + restimestampmock: 2024-08-02T22:15:47.228491803Z diff --git a/flask-redis/keploy/test-set-0/tests/test-1.yaml b/flask-redis/keploy/test-set-0/tests/test-1.yaml new file mode 100755 index 0000000..ddc1544 --- /dev/null +++ b/flask-redis/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,47 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/books/ + header: + Accept: '*/*' + Content-Length: "44" + Content-Type: application/json + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: '{"title": "1984", "author": "George Orwell"}' + timestamp: 2024-08-02T22:15:10.596402605Z + resp: + status_code: 201 + header: + Content-Length: "59" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:15:10 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "book_id": 1, + "message": "Book added successfully" + } + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-08-02T22:15:12.681157884Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1722636912 +curl: |- + curl --request POST \ + --url http://localhost:5000/books/ \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:5000' \ + --header 'User-Agent: curl/8.6.0' \ + --data '{"title": "1984", "author": "George Orwell"}' diff --git a/flask-redis/keploy/test-set-0/tests/test-2.yaml b/flask-redis/keploy/test-set-0/tests/test-2.yaml new file mode 100755 index 0000000..85115b2 --- /dev/null +++ b/flask-redis/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,50 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/books/?page=1&limit=10 + url_params: + limit: "10" + page: "1" + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:17.339856691Z + resp: + status_code: 200 + header: + Content-Length: "88" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:15:17 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "books": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-08-02T22:15:19.428364137Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1722636919 +curl: | + curl --request GET \ + --url http://localhost:5000/books/?page=1&limit=10 \ + --header 'Host: localhost:5000' \ + --header 'User-Agent: curl/8.6.0' \ + --header 'Accept: */*' \ diff --git a/flask-redis/keploy/test-set-0/tests/test-3.yaml b/flask-redis/keploy/test-set-0/tests/test-3.yaml new file mode 100755 index 0000000..316a90d --- /dev/null +++ b/flask-redis/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,43 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/books/1 + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:24.919087736Z + resp: + status_code: 200 + header: + Content-Length: "51" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:15:24 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "author": "George Orwell", + "title": "1984" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-08-02T22:15:26.965315001Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1722636926 +curl: | + curl --request GET \ + --url http://localhost:5000/books/1 \ + --header 'Accept: */*' \ + --header 'Host: localhost:5000' \ + --header 'User-Agent: curl/8.6.0' \ diff --git a/flask-redis/keploy/test-set-0/tests/test-4.yaml b/flask-redis/keploy/test-set-0/tests/test-4.yaml new file mode 100755 index 0000000..e659f2f --- /dev/null +++ b/flask-redis/keploy/test-set-0/tests/test-4.yaml @@ -0,0 +1,49 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-4 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/books/search?query=1984 + url_params: + query: "1984" + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:32.960447823Z + resp: + status_code: 200 + header: + Content-Length: "90" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:15:32 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "results": [ + { + "author": "George Orwell", + "title": "1984" + } + ] + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-08-02T22:15:34.98447863Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1722636934 +curl: | + curl --request GET \ + --url http://localhost:5000/books/search?query=1984 \ + --header 'Host: localhost:5000' \ + --header 'User-Agent: curl/8.6.0' \ + --header 'Accept: */*' \ diff --git a/flask-redis/keploy/test-set-0/tests/test-5.yaml b/flask-redis/keploy/test-set-0/tests/test-5.yaml new file mode 100755 index 0000000..7f38a10 --- /dev/null +++ b/flask-redis/keploy/test-set-0/tests/test-5.yaml @@ -0,0 +1,50 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-5 +spec: + metadata: {} + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/books/1 + header: + Accept: '*/*' + Content-Length: "54" + Content-Type: application/json + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: '{"title": "1984 - Updated", "author": "George Orwell"}' + timestamp: 2024-08-02T22:15:39.802018618Z + resp: + status_code: 200 + header: + Content-Length: "123" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:15:39 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "book": { + "author": "George Orwell", + "title": "1984 - Updated" + }, + "message": "Book updated successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-08-02T22:15:41.813988842Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1722636941 +curl: |- + curl --request PUT \ + --url http://localhost:5000/books/1 \ + --header 'Host: localhost:5000' \ + --header 'User-Agent: curl/8.6.0' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data '{"title": "1984 - Updated", "author": "George Orwell"}' diff --git a/flask-redis/keploy/test-set-0/tests/test-6.yaml b/flask-redis/keploy/test-set-0/tests/test-6.yaml new file mode 100755 index 0000000..228ce8e --- /dev/null +++ b/flask-redis/keploy/test-set-0/tests/test-6.yaml @@ -0,0 +1,42 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-6 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/books/1 + header: + Accept: '*/*' + Host: localhost:5000 + User-Agent: curl/8.6.0 + body: "" + timestamp: 2024-08-02T22:15:47.228393997Z + resp: + status_code: 200 + header: + Content-Length: "45" + Content-Type: application/json + Date: Fri, 02 Aug 2024 22:15:47 GMT + Server: Werkzeug/3.0.3 Python/3.10.14 + body: | + { + "message": "Book deleted successfully" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-08-02T22:15:49.269456095Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1722636949 +curl: | + curl --request DELETE \ + --url http://localhost:5000/books/1 \ + --header 'Accept: */*' \ + --header 'Host: localhost:5000' \ + --header 'User-Agent: curl/8.6.0' \ diff --git a/flask-redis/redisClient.py b/flask-redis/redisClient.py new file mode 100644 index 0000000..dc01e64 --- /dev/null +++ b/flask-redis/redisClient.py @@ -0,0 +1,12 @@ +import redis +import os + +# Connect to Redis server +client = redis.Redis( + host=os.getenv('REDIS_HOST', 'localhost'), + port=int(os.getenv('REDIS_PORT', 6379)), + db=0 +) + +def get_redis_client(): + return client diff --git a/flask-redis/requirements.txt b/flask-redis/requirements.txt new file mode 100644 index 0000000..bdb539d --- /dev/null +++ b/flask-redis/requirements.txt @@ -0,0 +1,3 @@ +Flask +redis +python-dotenv \ No newline at end of file diff --git a/flask-redis/routes/book_routes.py b/flask-redis/routes/book_routes.py new file mode 100644 index 0000000..6d58543 --- /dev/null +++ b/flask-redis/routes/book_routes.py @@ -0,0 +1,133 @@ +from flask import Blueprint, request, jsonify +from redisClient import get_redis_client +import json + +book = Blueprint('book', __name__) +redis_client = get_redis_client() + +@book.route('/', methods=['POST']) +def add_book(): + data = request.get_json() + title = data.get('title') + author = data.get('author') + + if not title or not author: + return jsonify({"error": "Title and author are required"}), 400 + + book_id = redis_client.incr('book_id') # Auto-increment ID for new book + redis_client.hset(f'book:{book_id}', mapping={"title": title, "author": author}) + + return jsonify({"message": "Book added successfully", "book_id": book_id}), 201 + + +@book.route('/', methods=['GET']) +def get_books(): + page = int(request.args.get('page', 1)) + limit = int(request.args.get('limit', 10)) + start = (page - 1) * limit + end = start + limit - 1 + + # Define your cache key here + cache_key = f'books_cache:page_{page}' + + # Check if the result is already in cache + cached_books = redis_client.get(cache_key) + if cached_books: + return jsonify(json.loads(cached_books)), 200 + + # If not cached, fetch from Redis + keys = redis_client.keys('book:*') + books = [ + {k.decode('utf-8'): v.decode('utf-8') for k, v in redis_client.hgetall(key).items()} + for key in keys + ] + redis_client.setex(cache_key, 300, json.dumps(books)) + + return jsonify({"books": books}), 200 + + +@book.route('/', methods=['GET']) +def get_book(book_id): + # Create a cache key based on the book ID + cache_key = f'book:{book_id}' + + # Check if the key exists in the cache + cached_book = redis_client.hgetall(cache_key) # Use hgetall for hash + + if cached_book: + # Decode the keys and values from bytes to strings + decoded_book = {key.decode('utf-8'): value.decode('utf-8') for key, value in cached_book.items()} + return jsonify(decoded_book), 200 + else: + return jsonify({"message": "Book not found"}), 404 + + +@book.route('/', methods=['PUT']) +def update_book(book_id): + data = request.get_json() + title = data.get('title') + author = data.get('author') + + if not redis_client.exists(f'book:{book_id}'): + return jsonify({"error": "Book not found"}), 404 + + if title: + redis_client.hset(f'book:{book_id}', "title", title) + if author: + redis_client.hset(f'book:{book_id}', "author", author) + + # Retrieve the updated book data + updated_book = { + "title": redis_client.hget(f'book:{book_id}', "title").decode('utf-8'), + "author": redis_client.hget(f'book:{book_id}', "author").decode('utf-8') + } + + # Update the cache with the latest data + redis_client.hmset(f'book:{book_id}', updated_book) + + return jsonify({"message": "Book updated successfully", "book": updated_book}), 200 + + + +@book.route('/', methods=['DELETE']) +def delete_book(book_id): + # Check if the book exists + if not redis_client.exists(f'book:{book_id}'): + return jsonify({"message": "Book not found"}), 404 + + # Delete the book + redis_client.delete(f'book:{book_id}') + + # Invalidate related caches + redis_client.delete(f'books_cache:page_*') # Adjust this if you cache other items + + return jsonify({"message": "Book deleted successfully"}), 200 + +@book.route('/search', methods=['GET']) +def search_books(): + query = request.args.get('query', '') + + if not query: + return jsonify({"error": "Search query is required"}), 400 + + cache_key = f'search:books:{query}' + cached_results = redis_client.get(cache_key) + + if cached_results: + return jsonify(json.loads(cached_results)), 200 + + all_books = redis_client.keys(f'book:*') + search_results = [] + + for book_key in all_books: + book_data = redis_client.hgetall(book_key) + title = book_data[b'title'].decode('utf-8') + author = book_data[b'author'].decode('utf-8') + if query.lower() in title.lower(): + search_results.append({"title": title, "author": author}) + + # Store search results in cache + redis_client.setex(cache_key, 300, json.dumps(search_results)) # Cache for 5 minutes + + return jsonify({"results": search_results}), 200 + From 1bd6f6e788c22021052222f0f2c96ccfd71293a7 Mon Sep 17 00:00:00 2001 From: Animesh Pathak <53110238+Sonichigo@users.noreply.github.com> Date: Wed, 4 Sep 2024 14:53:24 +0530 Subject: [PATCH 21/31] chore: remove test folder (#28) * Revert "fix: docker and readme instruction" This reverts commit f05aab2faccac2a915be4ae4e907a7b3d8c3e282. * fix: refactor flask-mongo change Signed-off-by: Animesh Pathak * feat: Created a sample app using flask and redis Signed-off-by: Aman172003 * feat: Created a sample app using flask and redis Signed-off-by: Aman172003 * changes Signed-off-by: Aman172003 * init Signed-off-by: Aman172003 * initialized Signed-off-by: Aman172003 * updated Signed-off-by: Aman172003 * removed errors Signed-off-by: Aman172003 * chore: remove keploy folder Signed-off-by: Animesh Pathak --------- Signed-off-by: Animesh Pathak Signed-off-by: Aman172003 Co-authored-by: Aman172003 --- django-postgres/README.md | 8 +- .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 201 bytes .../__pycache__/admin.cpython-311.pyc | Bin 0 -> 404 bytes .../__pycache__/apps.cpython-311.pyc | Bin 0 -> 582 bytes .../__pycache__/models.cpython-311.pyc | Bin 0 -> 1279 bytes .../__pycache__/serializers.cpython-311.pyc | Bin 0 -> 901 bytes .../__pycache__/urls.cpython-311.pyc | Bin 0 -> 520 bytes .../__pycache__/views.cpython-311.pyc | Bin 0 -> 4193 bytes .../__pycache__/0001_initial.cpython-311.pyc | Bin 0 -> 1341 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 212 bytes .../__pycache__/__init__.cpython-311.pyc | Bin 0 -> 205 bytes .../__pycache__/settings.cpython-311.pyc | Bin 0 -> 2778 bytes .../__pycache__/urls.cpython-311.pyc | Bin 0 -> 1266 bytes .../__pycache__/wsgi.cpython-311.pyc | Bin 0 -> 743 bytes .../django_postgres/docker-compose.yml | 2 +- .../keploy/test-set-0/mocks.yaml | 815 ------------- .../keploy/test-set-0/tests/test-1.yaml | 51 - .../keploy/test-set-0/tests/test-2.yaml | 43 - .../keploy/test-set-0/tests/test-3.yaml | 51 - .../keploy/test-set-0/tests/test-4.yaml | 43 - .../keploy/test-set-0/tests/test-5.yaml | 51 - .../keploy/test-set-0/tests/test-6.yaml | 43 - .../keploy/test-set-0/tests/test-7.yaml | 43 - .../keploy/testReports/report-1.yaml | 1081 ----------------- .../django_postgres/requirements.txt | 1 + 25 files changed, 6 insertions(+), 2226 deletions(-) create mode 100644 django-postgres/django_postgres/application/__pycache__/__init__.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/__pycache__/admin.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/__pycache__/apps.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/__pycache__/models.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/__pycache__/serializers.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/__pycache__/urls.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/__pycache__/views.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/migrations/__pycache__/0001_initial.cpython-311.pyc create mode 100644 django-postgres/django_postgres/application/migrations/__pycache__/__init__.cpython-311.pyc create mode 100644 django-postgres/django_postgres/django_postgres/__pycache__/__init__.cpython-311.pyc create mode 100644 django-postgres/django_postgres/django_postgres/__pycache__/settings.cpython-311.pyc create mode 100644 django-postgres/django_postgres/django_postgres/__pycache__/urls.cpython-311.pyc create mode 100644 django-postgres/django_postgres/django_postgres/__pycache__/wsgi.cpython-311.pyc delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/mocks.yaml delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/tests/test-1.yaml delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/tests/test-2.yaml delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/tests/test-3.yaml delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/tests/test-4.yaml delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/tests/test-5.yaml delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/tests/test-6.yaml delete mode 100755 django-postgres/django_postgres/keploy/test-set-0/tests/test-7.yaml delete mode 100755 django-postgres/django_postgres/keploy/testReports/report-1.yaml diff --git a/django-postgres/README.md b/django-postgres/README.md index 91161b4..1f04ac2 100644 --- a/django-postgres/README.md +++ b/django-postgres/README.md @@ -20,7 +20,7 @@ git clone https://github.com/keploy/samples-python.git && cd samples-python/djan Keploy can be installed on Linux directly and on Windows with the help of WSL. Based on your system architecture, install the keploy latest binary release ```bash - curl -O https://raw.githubusercontent.com/keploy/keploy/main/keploy.sh && source keploy.sh + curl -O https://keploy.io/install.sh && source install.sh keploy ``` @@ -92,13 +92,13 @@ This will return all the data saved in the database. ### Make a GET request to get a specific data ```bash -curl --location 'http://127.0.0.1:8000/user/c793c752-ad95-4cff-8cbe-5715a1e8a76e/' +curl --location 'http://127.0.0.1:8000/user/' ``` ### Make a PUT request to update a specific data ```bash -curl --location --request PUT 'http://127.0.0.1:8000/user/efbe12df-3cae-4cbc-b045-dc74840aa82b/' \ +curl --location --request PUT 'http://127.0.0.1:8000/user/' \ --header 'Content-Type: application/json' \ --data-raw ' { "name": "Jane Smith", @@ -111,7 +111,7 @@ curl --location --request PUT 'http://127.0.0.1:8000/user/efbe12df-3cae-4cbc-b04 ### Make a DELETE request to delete a specific data ```bash -curl --location --request DELETE 'http://127.0.0.1:8000/user/ee2af3fc-0503-4a6a-a452-b7d8c87a085b/' +curl --location --request DELETE 'http://127.0.0.1:8000/user/' ``` Now both these API calls were captured as **editable** testcases and written to `keploy/tests` folder. The keploy directory would also have `mocks` file that contains all the outputs of postgres operations. diff --git a/django-postgres/django_postgres/application/__pycache__/__init__.cpython-311.pyc b/django-postgres/django_postgres/application/__pycache__/__init__.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..cc721f23d69991b90ceb2d0ee8eb2fe0ce2e1a98 GIT binary patch literal 201 zcmZ3^%ge<81b-^0rGe6s7oYZ37g36MN{5<`Xti-(ZeBFZl;*#{D)M6+<9?nlJ zD9Fi7PAtg;s*R7&%*!l^kJl@x{Ka9Do1apelWJGQ3bYL5oML_;@qw9I}J+WY~;gv7=GVxS8Ou}NGxcCcNE?EC;GSeZbGKa(OP zs;o@iDs`(ExX=dC)3fj1+4tVP1VINdzKe(J8_ZudX~NkQ%Tp{KfdVB0GBP3rXp1_c zl{q7a03&0!8F})W>VIa=GXZ$Rvkshh&!F$kYuYE37txH%dHs&eJvU6B^!;j=jw6|< zVXUOp{7TpRRDPx?6GqoYm20?VRa>)!8_V=7EU^o#i!fCg3yqRIPB|(FE+@C4iLzWU zGsp{@DjBZT2e~pf(adc44fGCb{QwU-XsiGL literal 0 HcmV?d00001 diff --git a/django-postgres/django_postgres/application/__pycache__/apps.cpython-311.pyc b/django-postgres/django_postgres/application/__pycache__/apps.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..485ad77adf37ccbe77b4d0b4f4c147a64de6d54b GIT binary patch literal 582 zcmZutJx{|h5IrX;DwHB%Ky+YW>_DKHp#18-= z{!GUzD-&B$nGgf#Bzy_Z_W8Zs-Sg${>-9N6d+%R&Zt;H71SHMh8?o5D3JcYRivyP!zdDgT^ve}&|+LK|&@3zZ~{30cpt{@l!2bVCwTH>0_ za4lw{hLtU0vGCho;>)lQxm;ssUf7j3JGBGJxKQ@4-`zC>k;S9LZBMx248F3*c@3ajL*tW3xN z{1i@4)UI(h$&For0FrFrNQNW{Tef8nw%v zis{?lmKH^qIQ--(-(5Bs~?$C^=*4A69r5;rezls5tih5 z0LhD}^c$1X4VR!TJ%YW*%hd94QI3H+$CM?mdLnFb!e_U*+6AA%T5ksM3Z)W1T}6~4 zdW!88DguVjjnRth;8E&Ut#ZX$bw_Ng>Tixx)2Z2*KB?8cid!8;Yi4!TeNuC&w@NVW z`tZUxYc<;{o1Vq7@nssRab_T-9)U2fV5IAb%&EBN4bUmv-KhuZ2WKMHQZdicFrphm zmVuBjB8W&$j>u>gjTL0Jjp%=_A1P}!pZfiKy zaAUla9caD?vjeSxqdUjXgZCeT>|#5+7-kn6lO27qIUVYQt+7L&&*}4ReLmFZ8&jRa zP;)&j47H4-@nakqFeogw3rk^Psqw0lf7DzF^N(7kBNF82+WEOKKi8N!RV20l6x>vC z5hDLmG0C*}&_>X5Oqn9ycFdOgT0Ho;(qRt2to}Sb7SsNcJmwSPj!?+eX+n~u4tN+` e{X3v9xcZ+a(-KearfR;}8T%#1fB$1LO5iU{fku7+ literal 0 HcmV?d00001 diff --git a/django-postgres/django_postgres/application/__pycache__/serializers.cpython-311.pyc b/django-postgres/django_postgres/application/__pycache__/serializers.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..9dde19877d1cb82850b7a6cf2359c669c347b2b0 GIT binary patch literal 901 zcmZ`%J#*7Q5WUlvO(0)G0-2#_P!T&nfFTqNR7sPe5yg%0o$WIxOWes5OqGHnB^CJx zVHo~Q3JTAaP^ELmsXP?yN|B9bl0Dti?d|IA?bCf1#q1R< z&Il)*Dw5EMQo8{yxG(6yt3Ez=3Hb@Lw8-bd5eXZY=!VqZH$ux; z$M>!#YFjK;&`gTSs#14dX;uUnH?qwwcAo9H*Mw#<6&BWG)WF zz&07fB*yFtV@b+K3fB)9`#6eK8PO=N^&u#f4Z2b&Zhnv%o@~zA{WKA6lMZF4FMDZA z$>Hcz+r&wxgxSr;c|RSt`5+$l(%mdIc~1*-n&UrS*WOPRDcbd*8ofEspI%B z>6F}#SH=GI9nrD`vZKOl&~eVX8dL`LKWMyYHYn6IrL^k@DDCnRln1LHcHVqm{+$>4 t2@v4bFav<8ODUa@rx*2SLUu0d&opo;Hgr3FefMj7@2Uu1-;q*u^$*7{+LQnQ literal 0 HcmV?d00001 diff --git a/django-postgres/django_postgres/application/__pycache__/urls.cpython-311.pyc b/django-postgres/django_postgres/application/__pycache__/urls.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..3c1e8f8218a4906f0f8efa207dcfa9e7a074cbd4 GIT binary patch literal 520 zcmZ8cJ5K^Z5Z=Apg9Ac{ufoLAh8Vcc%0NuCl*W)4n#+Y<;K<%1yLT#9l$2Kb4>U%9 z%#l!#Ypv)=C`^cjvjQeKJ3G7I%r~#sVlj_Ez6Vd8FL*x{*hpsmS@hxaj3}a*BM-MQ zMpUCZ*F3$YW27O5DPek_Y!a#Qk$KS(dWXA`UrrV{#>PX<|D3MY%Fx_3D(7d4RK_U@ zov1g%D`4EZ>`p#p&*IpnH7h;nvdE4@>O{<@jI)R}B@-&kcRZG&bO#9MoZD@|fTMzq zayBi{zTw zz|3`w@e~~;+d4&i$+pf-WaNeyqr=C`$-b4GUL~Y4CXEScOo<8p-BEK=JWft(38{}s SeM0JULoaE=f;yrIt$qM(R*l~P literal 0 HcmV?d00001 diff --git a/django-postgres/django_postgres/application/__pycache__/views.cpython-311.pyc b/django-postgres/django_postgres/application/__pycache__/views.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..48caa6d7d45ce7f92e67e7462131f4886c1af8dd GIT binary patch literal 4193 zcmc&%YiJzT6~6P>oqdd69a}5OD|@wi#Cl})sMNHPE4$&$AO0B`JNZ#4vtmHYfFMx%!~Zrog*249=gvN7 zB9*qG?cF`ZX;oN42fT?zNR+mv&%C*hs!c_)`+!>w5>G;AMacLF!TB4tka6BrP9NDDHgSK63|{Q%QIEdk|jdx)Q-&~R{tzJO12xcT2tbopRLynYDa2q zMc;w&*$t+;hsdZ675zG6ohNQP$rwEcH)Vsl!ORrjtJEsG#>}Br%HjjI=z~9i52|+f z@9%qqg>lQf6&=mx#jdjp?oz{IMA>~aMthmTYjmr zulxV$7ZE{>slANJg@DjN$3=rnNQx3&lrXsf2Ahl~B*P&kqH)=9rK5_nn!;eTD!rz} zRq47JX98E!VpNsHwzelE5HcN7DkFpNZPRsFFl&rF!#9k$oUNcU@P8L>7rz{j!MZz)e zfVqjM6&Bod6Xl)ARd?&g?UVc5X^lIbr&;&lq0sh0$NPN;!J+-&(5|QjhqA#@Jvf>b z&grCvHzS9_soRm?j%|-=eB0NDbxnChxd$tRsOLUrJ__G+?l?7ne^waKg#nGX*RP@E z8R$yh_LX?uqlbcT``m%hzAvVgZ&T7l;i8)nSN{f*B7@gZeIMea3<5N^_|lK zKh6qcx&V6_EA3^J?4>{siP^^!yVSi4I~R5bcVF2Z-npa&ev}nn)P)x{-d;<48m-z> z(>~Xxac#uAqlbL`)};g9zt8(Ktj7DZe5cNL9`Jqpd|#Fi>3m4zL*}Ia<+ZtyD+r5H zeh#n=*j~@9wla0)yuFlB@=CPLo{&9nY z(9SS@;Vk;>tY<37d^XfM)yjPCqk#Xs)dAG}unqR*pUuq1%IOKrS%&lX;3gge=fC^U z;oKSmMS6$13-jD3!NDvW)H+oGxkXeA$PE^tW<|%hL#0|3a;wL%!nhey>r1mCWTpX@ z#6e_L5=n~1o<`W`EkX-@gErFucpsAnIEy>^;82cWQh6 zz}K_y>)GW#;UB!J4@7dIksbNL3wmfGH~7O({12A(!Rg$<3!t6T2d45IYU=$GF-_Cd zS0>&3$zNRPL@;wUEA;9@FTuRy@#4E~p#ix9uy$nv4&d#uE8K(j8U;doJmY?5Z@6{b z$2@GHfPd(75ZW6KMOx6K7SANlJnCqjq0kpfps4pZ9A!R9r)!2%vVDhy= z>XU+GKq+KBK1e3ig{v6SE6Au`4?)xXA6H0ynr&K9iluN=O<@I-&~13()))WUDTV85 zraI*Rf#EIAzND(@LT1D+Ly}`=ADG;-d*~@pWZuSaT<2g_E3!0(M?gj}LisBY$P6ed zhuSr3&7mgET63sRv(_96Y1W!U&uP}0LyelX=1_-btvTeqY5pKPp*=U7G*7TlvsAlI zwdZL+HTu!XJc3t+e90iXqomD`nH@Jre$%ztpQT!KswGdKpy0v)A(p2s5>t$aVfX(4 D%3YR# literal 0 HcmV?d00001 diff --git a/django-postgres/django_postgres/application/migrations/__pycache__/0001_initial.cpython-311.pyc b/django-postgres/django_postgres/application/migrations/__pycache__/0001_initial.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..b9c2567a205266514e6c832972180ba471f8bdc2 GIT binary patch literal 1341 zcmZuxzi-<{6h2ZUB~m{kscs#ql3So@T{W@g7MY5oC=l0y)5a*ANO9SLpmk@7GJln% zlE{;W4jnVK{tH|b@!&CIh7KNSfP-*TfM)SV!=8d7=-o+lQOI}V$M@cS@A%%`2mO)H zD}aoDhQIABrvUhyI>`{H#`!8Seg_ah&IA^xau%=h9QAoKrKWgr7r@jn01Alf3rX?; z+3h)bCPNh<{{S?^Q|dN&tXM|Z(*wh?eJoiHM5e#dnR3}HH+9Yxj(!^fm4iU#A*ZIg zKoxj^#J-dyKpv7RP`aPFjBrTqv(9J)a!`Qcp>#kxdY*Izc6gX(S=r0143rO*1D>$R zGZ}=HWvrwk0CO;Z1*sq?Hjb zZP-RYYR5T8_Rckx;Kd{ ztnjJrxM(WOKfyWK0KD04_8bc}eaALBJ)`R^n}$7j+VpkHHIcvM4uhU!H(_75yUvp9 z_(9i0{?yklecg3Uqr)WM{7?MNm6esxwP{1k?$D!}W{@U^|C+$)a=t2*M|Wd^o0CT0 z#~C1h@T(GK7RIIdSEYBu`Ne0Cqxr?7hc9pc^=0^z7Vf$+0N?QIJb7Ke$Dc90U`QgR z?|70JRvP>7MU}?U=F8o%vUyV3j4GR9@xi!sJ*?i`|0Js3Jo1lgVYPiyZAaC1SbQ`t zy&u+>_S;c?=|%bYv#{PeskfqfD=fChrD|BawZ9hCZoS}-7sA@sNo^~tZH2`j`vJ=dJ74``-obM|1q)NWWJin6s7oYZ37g36MN{5<`Xti-(ZeBFZl;*#{D)M6+<9?nlJ zD9Fi7PAtg;s?E(zF9NfQ_2c6+^D;}~6s7oYZ37g36MN{5<`Xti-(ZeBFZl;*#{D)M6+<9w$FO vJ~J<~BtBlRpz;@oO>TZlX-=wL5i8I_kdun}fy4)9Mn=XD3^1aI87Kw-Vq!R6 literal 0 HcmV?d00001 diff --git a/django-postgres/django_postgres/django_postgres/__pycache__/settings.cpython-311.pyc b/django-postgres/django_postgres/django_postgres/__pycache__/settings.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..64c167bb6de54b1a5a8df49a6bb68095c16f0da0 GIT binary patch literal 2778 zcmb7G&2!sC6qo!dJGSejPMUsD)E3%05Sg@T3k*|GY$Y{y>|i+!=pq#F+Syi?RIQve zI{64Q9Jq1ez;GzT^q(nAXPVI|Gn|;=pqbu!;>jP0$LS13mY#OszOVi5dr$r?olY`v zeL4HGwUuU=zkMK zqqLGi8FUI|(KP&K&}o$WIYwCJ6q-eIAUBK7^yz$`o+WHMqGZuIWg4AVX29oZcyj21 zGK=0(=Fml%$-k>D!ep)CXvq^=4k5L3ovs1uE0Sp!#(;`h;7zJJ!n0IzC-|Ff*uM_I< zX6txknt{L(CN{sT>0M0!k1rdy#vJ_}oNb=mbXB)5?UKdT?y|kN;HZ0dY#kZKuGa9_g*@lx29|`TX*f37 z7W%llrzg2xaC&}%8K_{xarP}t-7^!56jKUFpIqp`g4PC&bCVhloJ})05$aynEK4WN z{$U9)rh<6PD4Ir#w7m>uiKDh`t%LVW`%ymbE)Fer2tqpE(`+pC;UUhxAO|?XVEt&# zU7ieJ7_u;?FAsQQTKSVsAVE5&Ar$+s{}82iODF<)K=9s}=$(mJGyr@&4iV;n^$?OV z#mP;K;2l?9A3#2)b^8sQ0K6YP)S8c=hJ>$I16XTTP%LyzZz2_7K(2Fn5B?#&6|BQ)QjFj~t;y!eV(yf0NtUZhm6%N{3gY^eQFytdIO z*Q&BR+1`Xb+9p9}kFwm0Biz!uy5qhxi~(&Q<2dSyk99BJrP!uu+v7$|H~x{(|9O#H z%QtW2V_rt2gW{bQSmB#IF0vXK9o| zT_F`Z7eRwc+yvL66TsMYuuM8c*MgdQFpw~9_wL(TS|A#JEhbCqBnRr6=O zxT?aZLsh-F1r1s!+jbbB^*B`xI$FSoc4g|j*o#@vm<-3`Rzz6}(!@*3Qn4;I)cevm zUbG~wY_54}u~MmRNhLKnE7{AGt8xQaz<}J6z2thiRH{f@VqNl5^;)f=Zq_TsT6NV+ zG^F*7irA23FS{kLl>_-oxhMu{=p{;GLk!%?-n_WkxTlVCLVX}s%CK02>`hn1>e{Bb zCaJ|*NdklAbxBofkWL&Vl3HH+xa!4%QA2^q8(_H@c=u*X(yF*wX{cbirmmKyO6hmz zRq)w*{cT~#?BD`54bt2pZBx*R(S1^&8uSZH7p;9~$25jrWO0<%!}(FKIWZr7g#~N> zHTM~uOIOEt?E*Lq{x;DnP(RGFtRG6U5uXXjJj0%S&diVBevCduczJmK z$zJWHe2&RU>_K+sAUA)Q;(aE1B{N3C@m$hRq@ppO2}n4T4)qc~&*W}DXR_crnmL$R zI>??q$eugMUF;9${B%4E@&O4a`tp~V#Hr_5#Se$T2G^f#j8DEApVSAF+4O}F0O4O{ orssR72a>=M(Z#7x{{>MoO%9RYm%>s1|EoE%!C>^{$@#dQ|V$RYWwuPSjz=gNDtD z`dCHiD?Eke$Og>1-#k{}4LpTi#06@1!PlQ7Yr%aB9~&>9J;5GL`eBeUSA;adeaf&u zbd!MgQp!cZ2*)X-L*fbBFkTD@-pN>$xT$aWT!r&!?2yE{X>U4$rlH3j33ebncZ^4S zZVX(!V{B!KmrKvX=A<`leBbx6o8T}`DH9!x`;5jo9`)QbEjJ69IexRm%M4@!a~Z;? zknCW?G+Sj}0~(VSPTZK>F{N)>#)HV^yuAyF`E#s)Q$fXmFe${&6<2Z|1K0nkk$BtX zJxQ`*{ibL;@uJKRlK_g4$CIhaldkHsofig!6gVDB&t}aix{&kuDSj%vBIy!IOj;WtT z@bKN` x!&^t4qkAXX`l+@)(VDPz>Cikh$5&b>Ywgpu_K9YnYW7U8t*8f!^2e4z(NE?|fr|hD literal 0 HcmV?d00001 diff --git a/django-postgres/django_postgres/django_postgres/__pycache__/wsgi.cpython-311.pyc b/django-postgres/django_postgres/django_postgres/__pycache__/wsgi.cpython-311.pyc new file mode 100644 index 0000000000000000000000000000000000000000..a163e98a8bff9e2866a8aaa25c2c56345ceaf965 GIT binary patch literal 743 zcmZWn&ubGw6n?XtHoCPz#1@Z3=_O!xRXm9ZLTgB)=^+&*2%B|xvO8gRX4#pfO;0`e zH`uGEiu9jJr6BCZfG2N(-iiljyIqO;=I47e?|t8!H=kEmEzt67@^NsC0Dk03DV6KZ zMWi>!5I_$C6c`NkkX}t@#AeS#K+v$f37?iq=fyRs1WP9dz^NXEATWTKCt5izP0(8o zj4srd55HS)y3H2$1s~854@8QCp~pkvCPJz(B@!p87!qIEmeo?29B8{Xs)*pi(PPYe z&j|J;_HZnM5hD#o#)RRqm(r^v?!_d){l1qZjQXCUg7^D6-V2QuiHE?`&fCbmV zsl)@y$bBpcu_C1s`NVMo;Y+(=5oewjVi>*jK^{NW#PzwC^xsc3pBFzt)1tc=C0e_-rH++nqBwR?$+y<+lTl5c?DY%r6><&y_!{BS5tA_ z%n&lWU0k$%orj%=PfZP&RS6%{RPfBwjsY2XBc`&I1>`Sqku$q|r-{eJk%Ch{qM@)E z<)Z^fdU3*tY$OvE3GNgijj|@!`kxy8r{_fMWO8}qX;G19X-$LaKL_%yp5`V(Xl_(d zWe)jt2at7iGjB6^IQ_fN!1!Q&gSD@)HeI);4|dL=eGcs@v}d)AX>H@Iws~ILJX* Date: Thu, 5 Sep 2024 18:43:57 +0530 Subject: [PATCH 22/31] feat:update unit test file in flask mongo (#29) * feat:utg support * feat:utg support * feat:utg support * Update app.py --- flask-mongo/app.py | 2 +- flask-mongo/test_app.py | 73 +++++++++++++++++------------------------ 2 files changed, 31 insertions(+), 44 deletions(-) diff --git a/flask-mongo/app.py b/flask-mongo/app.py index 6f7172f..8a6418b 100644 --- a/flask-mongo/app.py +++ b/flask-mongo/app.py @@ -40,4 +40,4 @@ def delete_student(student_id): return jsonify({'message': 'Student deleted successfully'}) if __name__ == '__main__': - app.run(host='0.0.0.0', port=6000, debug=True) \ No newline at end of file + app.run(host='0.0.0.0', port=6000, debug=True) diff --git a/flask-mongo/test_app.py b/flask-mongo/test_app.py index 30cf13f..f07148a 100644 --- a/flask-mongo/test_app.py +++ b/flask-mongo/test_app.py @@ -1,45 +1,32 @@ -import unittest -from app import app -from unittest.mock import patch, MagicMock -import json -from bson import ObjectId +import pytest +from flask import Flask, json +from pymongo import MongoClient +from app import app as flask_app # Assuming your Flask app is saved as app.py + +@pytest.fixture +def client(): + with flask_app.test_client() as client: + yield client + + +def test_get_nonexistent_student(client): + student_id = '999' + response = client.get(f'/students/{student_id}') + assert response.status_code == 200 + data = json.loads(response.data) + assert data is None + + +def test_update_nonexistent_student(client): + student_id = '999' + updated_student = { + "name": "Nonexistent Student", + "age": 30, + "major": "Physics" + } + response = client.put(f'/students/{student_id}', json=updated_student) + assert response.status_code == 200 + data = json.loads(response.data) + assert data["message"] == "Student updated successfully" -class TestTaskManager(unittest.TestCase): - def setUp(self): - self.app = app.test_client() - self.app.testing = True - - self.collection_mock = MagicMock() - self.patcher = patch('app.collection', self.collection_mock) - self.patcher.start() - - def tearDown(self): - self.patcher.stop() - - def test_create_task(self): - data = {'title': 'Test Task', 'description': 'This is a test task'} - response = self.app.post('/api/tasks', json=data) - self.assertEqual(response.status_code, 201) - self.assertIn(b'Task created successfully', response.data) - - def test_get_all_tasks(self): - self.collection_mock.find.return_value = [] - response = self.app.get('/api/tasks') - self.assertEqual(response.status_code, 200) - self.assertEqual(json.loads(response.data)['tasks'], []) - - def test_update_task(self): - with patch('app.ObjectId', return_value='mocked_id'): - response = self.app.put('/api/tasks/mock_id', json={'title': 'Updated Task', 'description': 'This is an updated task'}) - self.assertEqual(response.status_code, 200) - self.assertIn(b'Task updated successfully', response.data) - - def test_delete_task(self): - with patch('app.ObjectId', return_value=ObjectId()): - response = self.app.delete('/api/tasks/mock_id') - self.assertEqual(response.status_code, 200) - self.assertIn(b'Task deleted successfully', response.data) - -if __name__ == '__main__': - unittest.main() From 123441859b5d222aade13b9fc956974ee99fc5bb Mon Sep 17 00:00:00 2001 From: Aryan Bakliwal <106430579+AryanBakliwal@users.noreply.github.com> Date: Thu, 24 Oct 2024 20:49:54 +0530 Subject: [PATCH 23/31] django-mongo sample app (#31) * sample django mongo app Signed-off-by: Aryan Bakliwal * add keploy tests Signed-off-by: Aryan Bakliwal <106430579+AryanBakliwal@users.noreply.github.com> --------- Signed-off-by: Aryan Bakliwal Signed-off-by: Aryan Bakliwal <106430579+AryanBakliwal@users.noreply.github.com> --- django-mongo/README.md | 92 ++++ .../django_mongo/django_mongo/__init__.py | 0 .../django_mongo/django_mongo/asgi.py | 16 + .../django_mongo/django_mongo/settings.py | 148 ++++++ .../django_mongo/django_mongo/urls.py | 23 + .../django_mongo/django_mongo/wsgi.py | 16 + .../django_mongo/inventory/__init__.py | 0 django-mongo/django_mongo/inventory/admin.py | 3 + django-mongo/django_mongo/inventory/apps.py | 6 + .../inventory/migrations/__init__.py | 0 django-mongo/django_mongo/inventory/models.py | 7 + .../django_mongo/inventory/serializers.py | 18 + django-mongo/django_mongo/inventory/tests.py | 3 + django-mongo/django_mongo/inventory/urls.py | 7 + django-mongo/django_mongo/inventory/views.py | 49 ++ django-mongo/django_mongo/keploy.yml | 61 +++ .../django_mongo/keploy/test-set-0/mocks.yaml | 490 ++++++++++++++++++ .../keploy/test-set-0/tests/test-1.yaml | 44 ++ .../keploy/test-set-0/tests/test-2.yaml | 53 ++ .../keploy/test-set-0/tests/test-3.yaml | 44 ++ .../keploy/test-set-0/tests/test-4.yaml | 48 ++ .../keploy/test-set-0/tests/test-5.yaml | 43 ++ django-mongo/django_mongo/manage.py | 22 + django-mongo/django_mongo/products.json | 32 ++ django-mongo/django_mongo/requirements.txt | 3 + 25 files changed, 1228 insertions(+) create mode 100644 django-mongo/README.md create mode 100644 django-mongo/django_mongo/django_mongo/__init__.py create mode 100644 django-mongo/django_mongo/django_mongo/asgi.py create mode 100644 django-mongo/django_mongo/django_mongo/settings.py create mode 100644 django-mongo/django_mongo/django_mongo/urls.py create mode 100644 django-mongo/django_mongo/django_mongo/wsgi.py create mode 100644 django-mongo/django_mongo/inventory/__init__.py create mode 100644 django-mongo/django_mongo/inventory/admin.py create mode 100644 django-mongo/django_mongo/inventory/apps.py create mode 100644 django-mongo/django_mongo/inventory/migrations/__init__.py create mode 100644 django-mongo/django_mongo/inventory/models.py create mode 100644 django-mongo/django_mongo/inventory/serializers.py create mode 100644 django-mongo/django_mongo/inventory/tests.py create mode 100644 django-mongo/django_mongo/inventory/urls.py create mode 100644 django-mongo/django_mongo/inventory/views.py create mode 100755 django-mongo/django_mongo/keploy.yml create mode 100755 django-mongo/django_mongo/keploy/test-set-0/mocks.yaml create mode 100755 django-mongo/django_mongo/keploy/test-set-0/tests/test-1.yaml create mode 100755 django-mongo/django_mongo/keploy/test-set-0/tests/test-2.yaml create mode 100755 django-mongo/django_mongo/keploy/test-set-0/tests/test-3.yaml create mode 100755 django-mongo/django_mongo/keploy/test-set-0/tests/test-4.yaml create mode 100755 django-mongo/django_mongo/keploy/test-set-0/tests/test-5.yaml create mode 100755 django-mongo/django_mongo/manage.py create mode 100644 django-mongo/django_mongo/products.json create mode 100644 django-mongo/django_mongo/requirements.txt diff --git a/django-mongo/README.md b/django-mongo/README.md new file mode 100644 index 0000000..ea2afb3 --- /dev/null +++ b/django-mongo/README.md @@ -0,0 +1,92 @@ +# Inventory Management Application + +## Overview + +A simple Django + MongoDB inventory management application using mongoengine and Django REST Framework to test Keploy integration capabilities using Django and MongoDB. +The endpoints available will be: + +1. `GET /api/items/` - List all items +2. `POST /api/items/` - Create a new item +3. `GET /api/items//` - Retrieve an item by ID +4. `PUT /api/items//` - Update an item by ID +5. `DELETE /api/items//` - Delete an item by ID + +## Requirements + +- Python 3.x +- Django +- mongoengine +- djangorestframework + +## Setup Instructions + +1. Clone the repository and navigate to project directory. + ```bash + git clone https://github.com/keploy/samples-python.git + cd samples-python/django-mongo/django_mongo + ``` +2. Install Keploy. + ```bash + curl --silent -O -L https://keploy.io/install.sh && source install.sh + ``` +3. Start MongoDB instance. + ```bash + docker pull mongo + docker run --name mongodb -d -p 27017:27017 -v mongo_data:/data/db -e MONGO_INITDB_ROOT_USERNAME= -e MONGO_INITDB_ROOT_PASSWORD= mongo + ``` +4. Set up Django appllication. + ```bash + python3 -m virtualenv venv + source venv/bin/activate + pip3 install -r requirements.txt + ``` +5. Capture the testcases. + ```bash + keploy record -c "python3 manage.py runserver" + ``` +6. Generate testcases by making API calls. + ```bash + # List items + # GET /api/items/ + curl -X GET http://localhost:8000/api/items/ + ``` + ```bash + # Create Item + # POST /api/items/ + curl -X POST http://localhost:8000/api/items/ \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Gadget C", + "quantity": 200, + "description": "A versatile gadget with numerous features." + }' + ``` + ```bash + # Retrieve Item + # GET /api/items// + curl -X GET http://localhost:8000/api/items// + ``` + ```bash + # Update Item + # PUT /api/items// + curl -X PUT http://localhost:8000/api/items/6142d21e122bda15f6f87b1d/ \ + -H "Content-Type: application/json" \ + -d '{ + "name": "Updated Widget A", + "quantity": 120, + "description": "An updated description for Widget A." + }' + ``` + ```bash + # Delete Item + # DELETE /api/items// + curl -X DELETE http://localhost:8000/api/items// + ``` + Replace `` with the actual ID of the item you want to retrieve, update, or delete. + +## Run the testcases + +Shut down MongoDB, Keploy doesn't need it during tests. +```bash +keploy test -c "python3 manage.py runserver" --delay 10 +``` \ No newline at end of file diff --git a/django-mongo/django_mongo/django_mongo/__init__.py b/django-mongo/django_mongo/django_mongo/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django-mongo/django_mongo/django_mongo/asgi.py b/django-mongo/django_mongo/django_mongo/asgi.py new file mode 100644 index 0000000..0f6b170 --- /dev/null +++ b/django-mongo/django_mongo/django_mongo/asgi.py @@ -0,0 +1,16 @@ +""" +ASGI config for django_mongo project. + +It exposes the ASGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/asgi/ +""" + +import os + +from django.core.asgi import get_asgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mongo.settings') + +application = get_asgi_application() diff --git a/django-mongo/django_mongo/django_mongo/settings.py b/django-mongo/django_mongo/django_mongo/settings.py new file mode 100644 index 0000000..3ade7c6 --- /dev/null +++ b/django-mongo/django_mongo/django_mongo/settings.py @@ -0,0 +1,148 @@ +""" +Django settings for django_mongo project. + +Generated by 'django-admin startproject' using Django 5.1.2. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/topics/settings/ + +For the full list of settings and their values, see +https://docs.djangoproject.com/en/5.1/ref/settings/ +""" + +from pathlib import Path +import mongoengine + +# Build paths inside the project like this: BASE_DIR / 'subdir'. +BASE_DIR = Path(__file__).resolve().parent.parent + + +# Quick-start development settings - unsuitable for production +# See https://docs.djangoproject.com/en/5.1/howto/deployment/checklist/ + +# SECURITY WARNING: keep the secret key used in production secret! +SECRET_KEY = 'django-insecure-3g@-x5(3t(i(p^qnu9lz3hk1u1yobrvwz($5^ucvnn0a6b$%ob' + +# SECURITY WARNING: don't run with debug turned on in production! +DEBUG = True + +ALLOWED_HOSTS = [] + + +# Application definition + +INSTALLED_APPS = [ + 'django.contrib.admin', + 'django.contrib.auth', + 'django.contrib.contenttypes', + 'django.contrib.sessions', + 'django.contrib.messages', + 'django.contrib.staticfiles', + 'rest_framework', + 'inventory', +] + +REST_FRAMEWORK = { + 'DEFAULT_PERMISSION_CLASSES': [ + 'rest_framework.permissions.AllowAny', + ], +} + +MIDDLEWARE = [ + 'django.middleware.security.SecurityMiddleware', + 'django.contrib.sessions.middleware.SessionMiddleware', + 'django.middleware.common.CommonMiddleware', + 'django.middleware.csrf.CsrfViewMiddleware', + 'django.contrib.auth.middleware.AuthenticationMiddleware', + 'django.contrib.messages.middleware.MessageMiddleware', + 'django.middleware.clickjacking.XFrameOptionsMiddleware', +] + +ROOT_URLCONF = 'django_mongo.urls' + +TEMPLATES = [ + { + 'BACKEND': 'django.template.backends.django.DjangoTemplates', + 'DIRS': [], + 'APP_DIRS': True, + 'OPTIONS': { + 'context_processors': [ + 'django.template.context_processors.debug', + 'django.template.context_processors.request', + 'django.contrib.auth.context_processors.auth', + 'django.contrib.messages.context_processors.messages', + ], + }, + }, +] + +WSGI_APPLICATION = 'django_mongo.wsgi.application' + + +# Database +# https://docs.djangoproject.com/en/5.1/ref/settings/#databases + +# DATABASES = { +# 'default': { +# 'ENGINE': 'django.db.backends.sqlite3', +# 'NAME': BASE_DIR / 'db.sqlite3', +# } +# } + + +# Password validation +# https://docs.djangoproject.com/en/5.1/ref/settings/#auth-password-validators + +AUTH_PASSWORD_VALIDATORS = [ + { + 'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator', + }, + { + 'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator', + }, +] + + +# Internationalization +# https://docs.djangoproject.com/en/5.1/topics/i18n/ + +LANGUAGE_CODE = 'en-us' + +TIME_ZONE = 'UTC' + +USE_I18N = True + +USE_TZ = True + + +# Static files (CSS, JavaScript, Images) +# https://docs.djangoproject.com/en/5.1/howto/static-files/ + +STATIC_URL = 'static/' + +# Default primary key field type +# https://docs.djangoproject.com/en/5.1/ref/settings/#default-auto-field + +DEFAULT_AUTO_FIELD = 'django.db.models.BigAutoField' + +# MongoDB configuration +MONGO_DB_NAME = 'inventory_db' +MONGO_USER = 'admin' +MONGO_PASSWORD = 'admin' +MONGO_HOST = 'localhost' +MONGO_PORT = 27017 + +# Connect to MongoDB +mongoengine.connect( + db=MONGO_DB_NAME, + username=MONGO_USER, + password=MONGO_PASSWORD, + host=MONGO_HOST, + port=MONGO_PORT +) \ No newline at end of file diff --git a/django-mongo/django_mongo/django_mongo/urls.py b/django-mongo/django_mongo/django_mongo/urls.py new file mode 100644 index 0000000..81af1ac --- /dev/null +++ b/django-mongo/django_mongo/django_mongo/urls.py @@ -0,0 +1,23 @@ +""" +URL configuration for django_mongo project. + +The `urlpatterns` list routes URLs to views. For more information please see: + https://docs.djangoproject.com/en/5.1/topics/http/urls/ +Examples: +Function views + 1. Add an import: from my_app import views + 2. Add a URL to urlpatterns: path('', views.home, name='home') +Class-based views + 1. Add an import: from other_app.views import Home + 2. Add a URL to urlpatterns: path('', Home.as_view(), name='home') +Including another URLconf + 1. Import the include() function: from django.urls import include, path + 2. Add a URL to urlpatterns: path('blog/', include('blog.urls')) +""" +from django.contrib import admin +from django.urls import path, include + +urlpatterns = [ + path('admin/', admin.site.urls), + path('api/', include('inventory.urls')), +] diff --git a/django-mongo/django_mongo/django_mongo/wsgi.py b/django-mongo/django_mongo/django_mongo/wsgi.py new file mode 100644 index 0000000..a13bfdb --- /dev/null +++ b/django-mongo/django_mongo/django_mongo/wsgi.py @@ -0,0 +1,16 @@ +""" +WSGI config for django_mongo project. + +It exposes the WSGI callable as a module-level variable named ``application``. + +For more information on this file, see +https://docs.djangoproject.com/en/5.1/howto/deployment/wsgi/ +""" + +import os + +from django.core.wsgi import get_wsgi_application + +os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mongo.settings') + +application = get_wsgi_application() diff --git a/django-mongo/django_mongo/inventory/__init__.py b/django-mongo/django_mongo/inventory/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django-mongo/django_mongo/inventory/admin.py b/django-mongo/django_mongo/inventory/admin.py new file mode 100644 index 0000000..8c38f3f --- /dev/null +++ b/django-mongo/django_mongo/inventory/admin.py @@ -0,0 +1,3 @@ +from django.contrib import admin + +# Register your models here. diff --git a/django-mongo/django_mongo/inventory/apps.py b/django-mongo/django_mongo/inventory/apps.py new file mode 100644 index 0000000..905749f --- /dev/null +++ b/django-mongo/django_mongo/inventory/apps.py @@ -0,0 +1,6 @@ +from django.apps import AppConfig + + +class InventoryConfig(AppConfig): + default_auto_field = 'django.db.models.BigAutoField' + name = 'inventory' diff --git a/django-mongo/django_mongo/inventory/migrations/__init__.py b/django-mongo/django_mongo/inventory/migrations/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/django-mongo/django_mongo/inventory/models.py b/django-mongo/django_mongo/inventory/models.py new file mode 100644 index 0000000..02dd773 --- /dev/null +++ b/django-mongo/django_mongo/inventory/models.py @@ -0,0 +1,7 @@ +from django.db import models +from mongoengine import Document, StringField, IntField + +class Item(Document): + name = StringField(required=True) + quantity = IntField(required=True) + description = StringField() \ No newline at end of file diff --git a/django-mongo/django_mongo/inventory/serializers.py b/django-mongo/django_mongo/inventory/serializers.py new file mode 100644 index 0000000..a178995 --- /dev/null +++ b/django-mongo/django_mongo/inventory/serializers.py @@ -0,0 +1,18 @@ +from rest_framework import serializers +from .models import Item + +class ItemSerializer(serializers.Serializer): + id = serializers.CharField(read_only=True) + name = serializers.CharField(required=True) + quantity = serializers.IntegerField(required=True) + description = serializers.CharField(required=False) + + def create(self, validated_data): + return Item(**validated_data).save() + + def update(self, instance, validated_data): + instance.name = validated_data.get('name', instance.name) + instance.quantity = validated_data.get('quantity', instance.quantity) + instance.description = validated_data.get('description', instance.description) + instance.save() + return instance diff --git a/django-mongo/django_mongo/inventory/tests.py b/django-mongo/django_mongo/inventory/tests.py new file mode 100644 index 0000000..7ce503c --- /dev/null +++ b/django-mongo/django_mongo/inventory/tests.py @@ -0,0 +1,3 @@ +from django.test import TestCase + +# Create your tests here. diff --git a/django-mongo/django_mongo/inventory/urls.py b/django-mongo/django_mongo/inventory/urls.py new file mode 100644 index 0000000..f35e225 --- /dev/null +++ b/django-mongo/django_mongo/inventory/urls.py @@ -0,0 +1,7 @@ +from django.urls import path +from .views import ItemViewSet + +urlpatterns = [ + path('items/', ItemViewSet.as_view({'get': 'list', 'post': 'create'})), + path('items//', ItemViewSet.as_view({'get': 'retrieve', 'put': 'update', 'delete': 'destroy'})), +] \ No newline at end of file diff --git a/django-mongo/django_mongo/inventory/views.py b/django-mongo/django_mongo/inventory/views.py new file mode 100644 index 0000000..6974df7 --- /dev/null +++ b/django-mongo/django_mongo/inventory/views.py @@ -0,0 +1,49 @@ +from django.shortcuts import render +from rest_framework import viewsets +from rest_framework.response import Response +from rest_framework import status +from .models import Item +from .serializers import ItemSerializer + +class ItemViewSet(viewsets.ViewSet): + + def list(self, request): + items = Item.objects.all() + serializer = ItemSerializer(items, many=True) + return Response(serializer.data) + + def create(self, request): + serializer = ItemSerializer(data=request.data) + if serializer.is_valid(): + item = Item(**serializer.validated_data) + item.save() + return Response(serializer.data, status=status.HTTP_201_CREATED) + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + + def retrieve(self, request, pk=None): + try: + item = Item.objects.get(id=pk) + serializer = ItemSerializer(item) + return Response(serializer.data) + except Item.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) + + def update(self, request, pk=None): + try: + item = Item.objects.get(id=pk) + serializer = ItemSerializer(item, data=request.data) + if serializer.is_valid(): + updated_item = serializer.save() # This will call the update method + return Response(ItemSerializer(updated_item).data) # Serialize the updated item + return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST) + except Item.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) + + + def destroy(self, request, pk=None): + try: + item = Item.objects.get(id=pk) + item.delete() + return Response(status=status.HTTP_204_NO_CONTENT) + except Item.DoesNotExist: + return Response(status=status.HTTP_404_NOT_FOUND) \ No newline at end of file diff --git a/django-mongo/django_mongo/keploy.yml b/django-mongo/django_mongo/keploy.yml new file mode 100755 index 0000000..481f26f --- /dev/null +++ b/django-mongo/django_mongo/keploy.yml @@ -0,0 +1,61 @@ +path: "" +appId: 0 +appName: django_mongo +command: python3 manage.py runserver +templatize: + testSets: [] +port: 0 +dnsPort: 26789 +proxyPort: 16789 +debug: false +disableTele: false +disableANSI: false +containerName: "" +networkName: "" +buildDelay: 30 +test: + selectedTests: {} + globalNoise: + global: {} + test-sets: {} + delay: 5 + host: "" + port: 0 + apiTimeout: 5 + skipCoverage: false + coverageReportPath: "" + ignoreOrdering: true + mongoPassword: default@123 + language: "" + removeUnusedMocks: false + fallBackOnMiss: false + jacocoAgentPath: "" + basePath: "" + mocking: true + ignoredTests: {} + disableLineCoverage: false + disableMockUpload: true + useLocalMock: false + updateTemplate: false +record: + filters: [] + recordTimer: 0s +configPath: "" +bypassRules: [] +generateGithubActions: false +keployContainer: keploy-v2 +keployNetwork: keploy-network +cmdType: native +contract: + services: [] + tests: [] + path: "" + download: false + generate: false + driven: consumer + mappings: + servicesMapping: {} + self: "" +inCi: false + +# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file. diff --git a/django-mongo/django_mongo/keploy/test-set-0/mocks.yaml b/django-mongo/django_mongo/keploy/test-set-0/mocks.yaml new file mode 100755 index 0000000..50d9642 --- /dev/null +++ b/django-mongo/django_mongo/keploy/test-set-0/mocks.yaml @@ -0,0 +1,490 @@ +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-0 +spec: + metadata: + operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo|c|MongoEngine","version": "4.10.1|0.29.1"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "6.5.0-1025-azure"},"platform": "CPython 3.12.1.final.0","env": {"container": {"runtime": "docker"}}}}, returnFieldsSelector: }' + type: config + requests: + - header: + length: 332 + requestId: 1804289383 + responseTo: 0 + Opcode: 2004 + message: + flags: 0 + collection_name: admin.$cmd + number_to_skip: 0 + number_to_return: -1 + query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo|c|MongoEngine","version":"4.10.1|0.29.1"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"6.5.0-1025-azure"},"platform":"CPython 3.12.1.final.0","env":{"container":{"runtime":"docker"}}}}' + return_fields_selector: "" + responses: + - header: + length: 329 + requestId: 125 + responseTo: 1804289383 + Opcode: 1 + message: + response_flags: 8 + cursor_id: 0 + starting_from: 0 + number_returned: 1 + documents: + - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6713fe1e569046d9af25b0b5"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1729364654276"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"20"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"25"},"readOnly":false,"ok":{"$numberDouble":"1.0"}}' + read_delay: 640736 + created: 1729364654 + reqTimestampMock: 2024-10-19T19:04:14.276667841Z + resTimestampMock: 2024-10-19T19:04:14.277439441Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-1 +spec: + metadata: + operation: '{ OpMsg flags: 65536, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"6713fe1e569046d9af25b0b5"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 134 + requestId: 846930886 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 65536 + sections: + - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"topologyVersion":{"processId":{"$oid":"6713fe1e569046d9af25b0b5"},"counter":{"$numberLong":"0"}},"maxAwaitTimeMS":{"$numberInt":"10000"},"$db":"admin"} }' + checksum: 0 + read_delay: 1789950 + responses: + - header: + length: 313 + requestId: 129 + responseTo: 846930886 + Opcode: 2013 + message: + flagBits: 2 + sections: + - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"6713fe1e569046d9af25b0b5"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1729364664289"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"20"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"25"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 10010192973 + created: 1729364664 + reqTimestampMock: 2024-10-19T19:04:14.279291948Z + resTimestampMock: 2024-10-19T19:04:24.289653646Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-2 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 52 + requestId: 1714636915 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"hello":{"$numberInt":"1"},"$db":"admin"} }' + checksum: 0 + read_delay: 10002211829 + responses: + - header: + length: 313 + requestId: 130 + responseTo: 1714636915 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"isWritablePrimary":true,"topologyVersion":{"processId":{"$oid":"6713fe1e569046d9af25b0b5"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1729364664291"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"21"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"25"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 238677 + created: 1729364664 + reqTimestampMock: 2024-10-19T19:04:24.291808444Z + resTimestampMock: 2024-10-19T19:04:24.292168839Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-3 +spec: + metadata: + operation: '{ OpQuery flags: [], fullCollectionName: admin.$cmd, numberToSkip: 0, numberToReturn: -1, query: {"ismaster": {"$numberInt":"1"},"helloOk": true,"client": {"driver": {"name": "PyMongo|c|MongoEngine","version": "4.10.1|0.29.1"},"os": {"type": "Linux","name": "Linux","architecture": "x86_64","version": "6.5.0-1025-azure"},"platform": "CPython 3.12.1.final.0","env": {"container": {"runtime": "docker"}}},"compression": [],"saslSupportedMechs": "admin.admin","speculativeAuthenticate": {"saslStart": {"$numberInt":"1"},"mechanism": "SCRAM-SHA-256","payload": {"$binary":{"base64":"biwsbj1hZG1pbixyPUlTVGRlTDJER25EeUd0MTMyM3dlbWo0d3BOTWZJRmhpalB6bThiUTk3ck09","subType":"00"}},"autoAuthorize": {"$numberInt":"1"},"options": {"skipEmptyExchange": true},"db": "admin"}}, returnFieldsSelector: }' + type: config + requests: + - header: + length: 598 + requestId: 1957747793 + responseTo: 0 + Opcode: 2004 + message: + flags: 0 + collection_name: admin.$cmd + number_to_skip: 0 + number_to_return: -1 + query: '{"ismaster":{"$numberInt":"1"},"helloOk":true,"client":{"driver":{"name":"PyMongo|c|MongoEngine","version":"4.10.1|0.29.1"},"os":{"type":"Linux","name":"Linux","architecture":"x86_64","version":"6.5.0-1025-azure"},"platform":"CPython 3.12.1.final.0","env":{"container":{"runtime":"docker"}}},"compression":[],"saslSupportedMechs":"admin.admin","speculativeAuthenticate":{"saslStart":{"$numberInt":"1"},"mechanism":"SCRAM-SHA-256","payload":{"$binary":{"base64":"biwsbj1hZG1pbixyPUlTVGRlTDJER25EeUd0MTMyM3dlbWo0d3BOTWZJRmhpalB6bThiUTk3ck09","subType":"00"}},"autoAuthorize":{"$numberInt":"1"},"options":{"skipEmptyExchange":true},"db":"admin"}}' + return_fields_selector: "" + responses: + - header: + length: 594 + requestId: 133 + responseTo: 1957747793 + Opcode: 1 + message: + response_flags: 8 + cursor_id: 0 + starting_from: 0 + number_returned: 1 + documents: + - '{"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6713fe1e569046d9af25b0b5"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1729364666167"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"24"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"25"},"readOnly":false,"saslSupportedMechs":["SCRAM-SHA-256","SCRAM-SHA-1"],"speculativeAuthenticate":{"conversationId":{"$numberInt":"1"},"done":false,"payload":{"$binary":{"base64":"cj1JU1RkZUwyREduRHlHdDEzMjN3ZW1qNHdwTk1mSUZoaWpQem04YlE5N3JNPS9lU1YzSWZBb3ZIemlUWXFJVHAwbWx5ZjgySzdydlZFLHM9OUtUMFQ5b0YrUlQzV0dFWmZTb3gzNXNZYng2d2RlZVNEeXpHWWc9PSxpPTE1MDAw","subType":"00"}}},"ok":{"$numberDouble":"1.0"}}' + read_delay: 802600 + created: 1729364666 + reqTimestampMock: 2024-10-19T19:04:26.166927988Z + resTimestampMock: 2024-10-19T19:04:26.167862404Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-4 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"saslContinue":{"$numberInt":"1"},"conversationId":{"$numberInt":"1"},"payload":{"$binary":{"base64":"Yz1iaXdzLHI9SVNUZGVMMkRHbkR5R3QxMzIzd2VtajR3cE5NZklGaGlqUHptOGJROTdyTT0vZVNWM0lmQW92SHppVFlxSVRwMG1seWY4Mks3cnZWRSxwPXlERG1PYzA1ZWdwaEpaallKZTY2MnEyWGs3SHNKS1VDaU1vVVV6SW5VTVk9","subType":"00"}},"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 225 + requestId: 424238335 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"saslContinue":{"$numberInt":"1"},"conversationId":{"$numberInt":"1"},"payload":{"$binary":{"base64":"Yz1iaXdzLHI9SVNUZGVMMkRHbkR5R3QxMzIzd2VtajR3cE5NZklGaGlqUHptOGJROTdyTT0vZVNWM0lmQW92SHppVFlxSVRwMG1seWY4Mks3cnZWRSxwPXlERG1PYzA1ZWdwaEpaallKZTY2MnEyWGs3SHNKS1VDaU1vVVV6SW5VTVk9","subType":"00"}},"$db":"admin"} }' + checksum: 0 + read_delay: 5086782 + responses: + - header: + length: 125 + requestId: 134 + responseTo: 424238335 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"conversationId":{"$numberInt":"1"},"done":true,"payload":{"$binary":{"base64":"dj1VUzhRbi8wbTErM1JoS2tNNmZRaHFqK2lRdGxIaUtXendmL3VKZXgwSVZRPQ==","subType":"00"}},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 304558 + created: 1729364666 + reqTimestampMock: 2024-10-19T19:04:26.173006844Z + resTimestampMock: 2024-10-19T19:04:26.173411679Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-5 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"item","filter":{},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }], checksum: 0 }' + requests: + - header: + length: 112 + requestId: 719885386 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"item","filter":{},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + checksum: 0 + read_delay: 572687 + responses: + - header: + length: 224 + requestId: 135 + responseTo: 719885386 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":{"$oid":"6713ff286b75650a56907678"},"name":"Gadget C","quantity":{"$numberInt":"200"},"description":"A versatile gadget with numerous features."}],"id":{"$numberLong":"0"},"ns":"inventory_db.item"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 492359 + created: 1729364666 + reqTimestampMock: 2024-10-19T19:04:26.174063774Z + resTimestampMock: 2024-10-19T19:04:26.174647202Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-6 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }], checksum: 0 }' + type: config + requests: + - header: + length: 65 + requestId: 1957747793 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"ismaster":{"$numberInt":"1"},"helloOk":true,"$db":"admin"} }' + checksum: 0 + read_delay: 10001778949 + responses: + - header: + length: 314 + requestId: 136 + responseTo: 1957747793 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"helloOk":true,"ismaster":true,"topologyVersion":{"processId":{"$oid":"6713fe1e569046d9af25b0b5"},"counter":{"$numberLong":"0"}},"maxBsonObjectSize":{"$numberInt":"16777216"},"maxMessageSizeBytes":{"$numberInt":"48000000"},"maxWriteBatchSize":{"$numberInt":"100000"},"localTime":{"$date":{"$numberLong":"1729364674294"}},"logicalSessionTimeoutMinutes":{"$numberInt":"30"},"connectionId":{"$numberInt":"21"},"minWireVersion":{"$numberInt":"0"},"maxWireVersion":{"$numberInt":"25"},"readOnly":false,"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 370160 + created: 1729364674 + reqTimestampMock: 2024-10-19T19:04:34.294047203Z + resTimestampMock: 2024-10-19T19:04:34.294532769Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-7 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"insert":"item","ordered":true,"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }, { SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"671402e72887cb944c43b8ba"},"name":"Gadget C","quantity":{"$numberInt":"200"},"description":"A versatile gadget with numerous features."} ] }], checksum: 0 }' + requests: + - header: + length: 241 + requestId: 1350490027 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"insert":"item","ordered":true,"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + - '{ SectionSingle identifier: documents , msgs: [ {"_id":{"$oid":"671402e72887cb944c43b8ba"},"name":"Gadget C","quantity":{"$numberInt":"200"},"description":"A versatile gadget with numerous features."} ] }' + checksum: 0 + read_delay: 45695442201 + responses: + - header: + length: 45 + requestId: 157 + responseTo: 1350490027 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 498127 + created: 1729364711 + reqTimestampMock: 2024-10-19T19:05:11.870212614Z + resTimestampMock: 2024-10-19T19:05:11.870816598Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-8 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"item","filter":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"2"},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }], checksum: 0 }' + requests: + - header: + length: 140 + requestId: 1365180540 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"item","filter":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"2"},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + checksum: 0 + read_delay: 39270780350 + responses: + - header: + length: 224 + requestId: 174 + responseTo: 1365180540 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":{"$oid":"6713ff286b75650a56907678"},"name":"Gadget C","quantity":{"$numberInt":"200"},"description":"A versatile gadget with numerous features."}],"id":{"$numberLong":"0"},"ns":"inventory_db.item"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 407362 + created: 1729364751 + reqTimestampMock: 2024-10-19T19:05:51.141679843Z + resTimestampMock: 2024-10-19T19:05:51.142418243Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-9 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"item","filter":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"2"},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }], checksum: 0 }' + requests: + - header: + length: 140 + requestId: 233665123 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"item","filter":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"2"},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + checksum: 0 + read_delay: 99571750729 + responses: + - header: + length: 224 + requestId: 215 + responseTo: 233665123 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":{"$oid":"6713ff286b75650a56907678"},"name":"Gadget C","quantity":{"$numberInt":"200"},"description":"A versatile gadget with numerous features."}],"id":{"$numberLong":"0"},"ns":"inventory_db.item"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 421459 + created: 1729364850 + reqTimestampMock: 2024-10-19T19:07:30.714254912Z + resTimestampMock: 2024-10-19T19:07:30.714797717Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-10 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"update":"item","ordered":true,"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }, { SectionSingle identifier: updates , msgs: [ {"q":{"_id":{"$oid":"6713ff286b75650a56907678"}},"u":{"$set":{"name":"Updated Widget A","quantity":{"$numberInt":"120"},"description":"An updated description for Widget A."}},"multi":false,"upsert":true} ] }], checksum: 0 }' + requests: + - header: + length: 285 + requestId: 2145174067 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"update":"item","ordered":true,"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + - '{ SectionSingle identifier: updates , msgs: [ {"q":{"_id":{"$oid":"6713ff286b75650a56907678"}},"u":{"$set":{"name":"Updated Widget A","quantity":{"$numberInt":"120"},"description":"An updated description for Widget A."}},"multi":false,"upsert":true} ] }' + checksum: 0 + read_delay: 1179499 + responses: + - header: + length: 60 + requestId: 216 + responseTo: 2145174067 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"nModified":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 511395 + created: 1729364850 + reqTimestampMock: 2024-10-19T19:07:30.716062926Z + resTimestampMock: 2024-10-19T19:07:30.716661092Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-11 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"item","filter":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"2"},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }], checksum: 0 }' + requests: + - header: + length: 140 + requestId: 1369133069 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"item","filter":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"2"},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + checksum: 0 + read_delay: 49267790804 + responses: + - header: + length: 226 + requestId: 237 + responseTo: 1369133069 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":{"$oid":"6713ff286b75650a56907678"},"name":"Updated Widget A","quantity":{"$numberInt":"120"},"description":"An updated description for Widget A."}],"id":{"$numberLong":"0"},"ns":"inventory_db.item"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 458793 + created: 1729364899 + reqTimestampMock: 2024-10-19T19:08:19.984540733Z + resTimestampMock: 2024-10-19T19:08:19.98511404Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-12 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"delete":"item","ordered":true,"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }, { SectionSingle identifier: deletes , msgs: [ {"q":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"0"}} ] }], checksum: 0 }' + requests: + - header: + length: 165 + requestId: 1125898167 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"delete":"item","ordered":true,"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + - '{ SectionSingle identifier: deletes , msgs: [ {"q":{"_id":{"$oid":"6713ff286b75650a56907678"}},"limit":{"$numberInt":"0"}} ] }' + checksum: 0 + read_delay: 750270 + responses: + - header: + length: 45 + requestId: 238 + responseTo: 1125898167 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"n":{"$numberInt":"1"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 377687 + created: 1729364899 + reqTimestampMock: 2024-10-19T19:08:19.985934962Z + resTimestampMock: 2024-10-19T19:08:19.986405462Z +--- +version: api.keploy.io/v1beta1 +kind: Mongo +name: mock-13 +spec: + metadata: + operation: '{ OpMsg flags: 0, sections: [{ SectionSingle msg: {"find":"item","filter":{},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }], checksum: 0 }' + requests: + - header: + length: 112 + requestId: 2089018456 + responseTo: 0 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"find":"item","filter":{},"lsid":{"id":{"$binary":{"base64":"czkuEpfTSBak1dx74/p4iA==","subType":"04"}}},"$db":"inventory_db"} }' + checksum: 0 + read_delay: 8085196300 + responses: + - header: + length: 224 + requestId: 243 + responseTo: 2089018456 + Opcode: 2013 + message: + flagBits: 0 + sections: + - '{ SectionSingle msg: {"cursor":{"firstBatch":[{"_id":{"$oid":"671402e72887cb944c43b8ba"},"name":"Gadget C","quantity":{"$numberInt":"200"},"description":"A versatile gadget with numerous features."}],"id":{"$numberLong":"0"},"ns":"inventory_db.item"},"ok":{"$numberDouble":"1.0"}} }' + checksum: 0 + read_delay: 486370 + created: 1729364908 + reqTimestampMock: 2024-10-19T19:08:28.071683686Z + resTimestampMock: 2024-10-19T19:08:28.072290581Z diff --git a/django-mongo/django_mongo/keploy/test-set-0/tests/test-1.yaml b/django-mongo/django_mongo/keploy/test-set-0/tests/test-1.yaml new file mode 100755 index 0000000..47b6d72 --- /dev/null +++ b/django-mongo/django_mongo/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,44 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/api/items/ + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/7.68.0 + body: "" + timestamp: 2024-10-19T19:04:26.158535156Z + resp: + status_code: 200 + header: + Allow: GET, POST, HEAD, OPTIONS + Content-Length: "127" + Content-Type: application/json + Date: Sat, 19 Oct 2024 19:04:26 GMT + Referrer-Policy: same-origin + Server: WSGIServer/0.2 CPython/3.12.1 + Vary: Accept, Cookie + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + body: '[{"id":"6713ff286b75650a56907678","name":"Gadget C","quantity":200,"description":"A versatile gadget with numerous features."}]' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-19T19:04:28.257078042Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1729364668 +curl: | + curl --request GET \ + --url http://localhost:8000/api/items/ \ + --header 'Accept: */*' \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/7.68.0' \ diff --git a/django-mongo/django_mongo/keploy/test-set-0/tests/test-2.yaml b/django-mongo/django_mongo/keploy/test-set-0/tests/test-2.yaml new file mode 100755 index 0000000..3c83896 --- /dev/null +++ b/django-mongo/django_mongo/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,53 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/api/items/ + header: + Accept: '*/*' + Content-Length: "113" + Content-Type: application/json + Host: localhost:8000 + User-Agent: curl/7.68.0 + body: |- + { + "name": "Gadget C", + "quantity": 200, + "description": "A versatile gadget with numerous features." + } + timestamp: 2024-10-19T19:05:11.862316346Z + resp: + status_code: 201 + header: + Allow: GET, POST, HEAD, OPTIONS + Content-Length: "93" + Content-Type: application/json + Date: Sat, 19 Oct 2024 19:05:11 GMT + Referrer-Policy: same-origin + Server: WSGIServer/0.2 CPython/3.12.1 + Vary: Accept, Cookie + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + body: '{"name":"Gadget C","quantity":200,"description":"A versatile gadget with numerous features."}' + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-19T19:05:13.966578004Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1729364713 +curl: |- + curl --request POST \ + --url http://localhost:8000/api/items/ \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/7.68.0' \ + --header 'Accept: */*' \ + --data "{\n \"name\": \"Gadget C\",\n \"quantity\": 200,\n \"description\": \"A versatile gadget with numerous features.\"\n }" diff --git a/django-mongo/django_mongo/keploy/test-set-0/tests/test-3.yaml b/django-mongo/django_mongo/keploy/test-set-0/tests/test-3.yaml new file mode 100755 index 0000000..f9ef6f5 --- /dev/null +++ b/django-mongo/django_mongo/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,44 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/api/items/6713ff286b75650a56907678/ + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/7.68.0 + body: "" + timestamp: 2024-10-19T19:05:51.140167751Z + resp: + status_code: 200 + header: + Allow: GET, PUT, DELETE, HEAD, OPTIONS + Content-Length: "125" + Content-Type: application/json + Date: Sat, 19 Oct 2024 19:05:51 GMT + Referrer-Policy: same-origin + Server: WSGIServer/0.2 CPython/3.12.1 + Vary: Accept, Cookie + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + body: '{"id":"6713ff286b75650a56907678","name":"Gadget C","quantity":200,"description":"A versatile gadget with numerous features."}' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-19T19:05:53.163490949Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1729364753 +curl: | + curl --request GET \ + --url http://localhost:8000/api/items/6713ff286b75650a56907678/ \ + --header 'User-Agent: curl/7.68.0' \ + --header 'Accept: */*' \ + --header 'Host: localhost:8000' \ diff --git a/django-mongo/django_mongo/keploy/test-set-0/tests/test-4.yaml b/django-mongo/django_mongo/keploy/test-set-0/tests/test-4.yaml new file mode 100755 index 0000000..5b841a2 --- /dev/null +++ b/django-mongo/django_mongo/keploy/test-set-0/tests/test-4.yaml @@ -0,0 +1,48 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-4 +spec: + metadata: {} + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/api/items/6713ff286b75650a56907678/ + header: + Accept: '*/*' + Content-Length: "110" + Content-Type: application/json + Host: localhost:8000 + User-Agent: curl/7.68.0 + body: '{ "name": "Updated Widget A", "quantity": 120, "description": "An updated description for Widget A."}' + timestamp: 2024-10-19T19:07:30.712800581Z + resp: + status_code: 200 + header: + Allow: GET, PUT, DELETE, HEAD, OPTIONS + Content-Length: "127" + Content-Type: application/json + Date: Sat, 19 Oct 2024 19:07:30 GMT + Referrer-Policy: same-origin + Server: WSGIServer/0.2 CPython/3.12.1 + Vary: Accept, Cookie + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + body: '{"id":"6713ff286b75650a56907678","name":"Updated Widget A","quantity":120,"description":"An updated description for Widget A."}' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-19T19:07:32.720391721Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1729364852 +curl: |- + curl --request PUT \ + --url http://localhost:8000/api/items/6713ff286b75650a56907678/ \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/7.68.0' \ + --data "{ \"name\": \"Updated Widget A\", \"quantity\": 120, \"description\": \"An updated description for Widget A.\"}" diff --git a/django-mongo/django_mongo/keploy/test-set-0/tests/test-5.yaml b/django-mongo/django_mongo/keploy/test-set-0/tests/test-5.yaml new file mode 100755 index 0000000..8bd7999 --- /dev/null +++ b/django-mongo/django_mongo/keploy/test-set-0/tests/test-5.yaml @@ -0,0 +1,43 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-5 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/api/items/6713ff286b75650a56907678/ + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/7.68.0 + body: "" + timestamp: 2024-10-19T19:08:19.983000488Z + resp: + status_code: 204 + header: + Allow: GET, PUT, DELETE, HEAD, OPTIONS + Content-Length: "0" + Date: Sat, 19 Oct 2024 19:08:19 GMT + Referrer-Policy: same-origin + Server: WSGIServer/0.2 CPython/3.12.1 + Vary: Accept, Cookie + X-Content-Type-Options: nosniff + X-Frame-Options: DENY + body: "" + status_message: No Content + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-19T19:08:22.044354383Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1729364902 +curl: | + curl --request DELETE \ + --url http://localhost:8000/api/items/6713ff286b75650a56907678/ \ + --header 'User-Agent: curl/7.68.0' \ + --header 'Accept: */*' \ + --header 'Host: localhost:8000' \ diff --git a/django-mongo/django_mongo/manage.py b/django-mongo/django_mongo/manage.py new file mode 100755 index 0000000..f3fd315 --- /dev/null +++ b/django-mongo/django_mongo/manage.py @@ -0,0 +1,22 @@ +#!/usr/bin/env python +"""Django's command-line utility for administrative tasks.""" +import os +import sys + + +def main(): + """Run administrative tasks.""" + os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'django_mongo.settings') + try: + from django.core.management import execute_from_command_line + except ImportError as exc: + raise ImportError( + "Couldn't import Django. Are you sure it's installed and " + "available on your PYTHONPATH environment variable? Did you " + "forget to activate a virtual environment?" + ) from exc + execute_from_command_line(sys.argv) + + +if __name__ == '__main__': + main() diff --git a/django-mongo/django_mongo/products.json b/django-mongo/django_mongo/products.json new file mode 100644 index 0000000..1099bda --- /dev/null +++ b/django-mongo/django_mongo/products.json @@ -0,0 +1,32 @@ +[ + { + "name": "Widget A", + "quantity": 100, + "description": "A high-quality widget that serves many purposes." + }, + { + "name": "Widget B", + "quantity": 150, + "description": "An essential widget for every toolkit." + }, + { + "name": "Gadget C", + "quantity": 200, + "description": "A versatile gadget with numerous features." + }, + { + "name": "Gadget D", + "quantity": 50, + "description": "A compact gadget perfect for small spaces." + }, + { + "name": "Tool E", + "quantity": 75, + "description": "A durable tool designed for heavy use." + }, + { + "name": "Tool F", + "quantity": 120, + "description": "An ergonomic tool for comfortable handling." + } +] \ No newline at end of file diff --git a/django-mongo/django_mongo/requirements.txt b/django-mongo/django_mongo/requirements.txt new file mode 100644 index 0000000..cc08838 --- /dev/null +++ b/django-mongo/django_mongo/requirements.txt @@ -0,0 +1,3 @@ +Django>=3.2,<4.0 +djangorestframework>=3.12,<4.0 +mongoengine>=0.20,<1.0 \ No newline at end of file From aa1cafb3dc116b579311b2e72014dce21bbc8b66 Mon Sep 17 00:00:00 2001 From: Harsh Joshi Date: Mon, 28 Oct 2024 11:49:51 +0530 Subject: [PATCH 24/31] added sample app (#32) * added sample app Signed-off-by: Harshjosh361 * updated dependency, installed python dotenv Signed-off-by: Harshjosh361 --------- Signed-off-by: Harshjosh361 --- flask_postgresql_app/.env | 2 + flask_postgresql_app/Dockerfile | 18 + flask_postgresql_app/README.md | 81 ++ flask_postgresql_app/app.py | 77 + flask_postgresql_app/docker-compose.yml | 23 + flask_postgresql_app/keploy.yml | 61 + flask_postgresql_app/keploy/.gitignore | 2 + .../keploy/test-set-0/mocks.yaml | 1246 +++++++++++++++++ .../keploy/test-set-0/tests/test-1.yaml | 53 + .../keploy/test-set-0/tests/test-2.yaml | 50 + .../keploy/test-set-0/tests/test-3.yaml | 53 + .../keploy/test-set-0/tests/test-4.yaml | 53 + .../keploy/test-set-0/tests/test-5.yaml | 50 + .../keploy/test-set-0/tests/test-6.yaml | 53 + .../keploy/test-set-0/tests/test-7.yaml | 54 + flask_postgresql_app/requirements.txt | 6 + 16 files changed, 1882 insertions(+) create mode 100644 flask_postgresql_app/.env create mode 100644 flask_postgresql_app/Dockerfile create mode 100644 flask_postgresql_app/README.md create mode 100644 flask_postgresql_app/app.py create mode 100644 flask_postgresql_app/docker-compose.yml create mode 100755 flask_postgresql_app/keploy.yml create mode 100644 flask_postgresql_app/keploy/.gitignore create mode 100755 flask_postgresql_app/keploy/test-set-0/mocks.yaml create mode 100755 flask_postgresql_app/keploy/test-set-0/tests/test-1.yaml create mode 100755 flask_postgresql_app/keploy/test-set-0/tests/test-2.yaml create mode 100755 flask_postgresql_app/keploy/test-set-0/tests/test-3.yaml create mode 100755 flask_postgresql_app/keploy/test-set-0/tests/test-4.yaml create mode 100755 flask_postgresql_app/keploy/test-set-0/tests/test-5.yaml create mode 100755 flask_postgresql_app/keploy/test-set-0/tests/test-6.yaml create mode 100755 flask_postgresql_app/keploy/test-set-0/tests/test-7.yaml create mode 100644 flask_postgresql_app/requirements.txt diff --git a/flask_postgresql_app/.env b/flask_postgresql_app/.env new file mode 100644 index 0000000..e6f528c --- /dev/null +++ b/flask_postgresql_app/.env @@ -0,0 +1,2 @@ +FLASK_ENV=development +DATABASE_URL=postgresql://flaskuser:password@db:5432/flaskdb diff --git a/flask_postgresql_app/Dockerfile b/flask_postgresql_app/Dockerfile new file mode 100644 index 0000000..9c4f754 --- /dev/null +++ b/flask_postgresql_app/Dockerfile @@ -0,0 +1,18 @@ + +FROM python:3.9-slim + + +WORKDIR /usr/src/app + +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +# Copy the rest of the working directory contents +COPY . . + +EXPOSE 5000 + +# env +ENV FLASK_APP=app.py + +CMD ["flask", "run", "--host=0.0.0.0"] diff --git a/flask_postgresql_app/README.md b/flask_postgresql_app/README.md new file mode 100644 index 0000000..e41dbc3 --- /dev/null +++ b/flask_postgresql_app/README.md @@ -0,0 +1,81 @@ +# User Management API + + +## Overview + +This is a Flask-based web application that uses PostgreSQL as its database. The project is containerized using Docker and Docker Compose for easy deployment and management. +The endpoints available will be: + +1. `GET /` - Home Route +2. `GET /users` - List all users +3. `POST /users` - Create a new user +4. `PUT /users/` - Update a user +5. `DELETE /users//` - Delete a user + + + +## Setup Instructions + +1. Clone the repository and navigate to project directory. + ```bash + git clone https://github.com/keploy/samples-python.git + cd samples-python/flask_postgresql_app + ``` +2. Install Keploy. + ```bash + curl --silent -O -L https://keploy.io/install.sh && source install.sh + ``` +3. Build and run the Docker containers: + ```bash + docker compose up --build + ``` +4. Access the application: + Once the containers are running, the Flask app will be available at: + ```bash + http://localhost:5000 + ``` +5. Capture the testcases. + ```bash + keploy record -c "docker compose up" --container-name "flask_web_app" + ``` +6. Generate testcases by making API calls. + ### Home Route + # GET / + ```bash + curl -X GET http://localhost:5000 + ``` + ```bash + # Retrieves a list of all users. + # GET /users + curl -X GET http://localhost:5000/users \ + ``` + ```bash + # Create a new user by providing a name. + # POST /users + curl -X POST http://localhost:5000/users -H "Content-Type: application/json" -d '{"name": "Harsh"}' + + ``` + ```bash + # Retrieve a user by their ID. + # GET /users/ + curl -X GET http://localhost:8000/users// \ + + ``` + ```bash + # Update the name of a user by their ID. + # PUT /users/ + curl -X PUT http://localhost:5000/users/ -H "Content-Type: application/json" -d '{"name": "Updated Name"}' + ``` + ```bash + # Delete a user by their ID + # DELETE / + curl -X DELETE http://localhost:5000/users/ + ``` + ```bash + Replace `` with the actual ID of the item you want to retrieve, update, or delete. + +## Run the testcases +```bash +keploy test -c "docker compose up" --container-name "flask_web_app" +``` + diff --git a/flask_postgresql_app/app.py b/flask_postgresql_app/app.py new file mode 100644 index 0000000..cce0ca9 --- /dev/null +++ b/flask_postgresql_app/app.py @@ -0,0 +1,77 @@ +from flask import Flask, jsonify, request +from flask_sqlalchemy import SQLAlchemy +from dotenv import load_dotenv +import os + +# Load environment variables from .env file +load_dotenv() + +app = Flask(__name__) +app.config['SQLALCHEMY_DATABASE_URI'] = os.getenv('DATABASE_URL') +app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False + +db = SQLAlchemy(app) + +class User(db.Model): + __tablename__ = 'users' + id = db.Column(db.Integer, primary_key=True) + name = db.Column(db.String(80), nullable=False) + + def __init__(self, name): + self.name = name + +# Create the database tables +@app.before_request +def create_tables(): + db.create_all() + +# Home route +@app.route('/', methods=['GET']) +def home(): + return jsonify({"message": "Welcome to the User Management API!"}), 200 + +# GET all users +@app.route('/users', methods=['GET']) +def get_users(): + users = User.query.all() + return jsonify([{'id': user.id, 'name': user.name} for user in users]) + +# POST a new user +@app.route('/users', methods=['POST']) +def add_user(): + name = request.json.get('name') + if not name: + return jsonify({"error": "Name is required."}), 400 + user = User(name=name) + db.session.add(user) + db.session.commit() + return jsonify({"message": f"User {name} added.", "id": user.id}), 201 + +# PUT to update a user +@app.route('/users/', methods=['PUT']) +def update_user(id): + user = User.query.get(id) + if user is None: + return jsonify({"error": "User not found."}), 404 + + name = request.json.get('name') + if name: + user.name = name + db.session.commit() + return jsonify({"message": f"User {id} updated."}) + + return jsonify({"error": "Name is required."}), 400 + +# DELETE a user +@app.route('/users/', methods=['DELETE']) +def delete_user(id): + user = User.query.get(id) + if user is None: + return jsonify({"error": "User not found."}), 404 + + db.session.delete(user) + db.session.commit() + return jsonify({"message": f"User {id} deleted."}) + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=5000) diff --git a/flask_postgresql_app/docker-compose.yml b/flask_postgresql_app/docker-compose.yml new file mode 100644 index 0000000..f35f9c5 --- /dev/null +++ b/flask_postgresql_app/docker-compose.yml @@ -0,0 +1,23 @@ +services: + web: + build: . + container_name: flask_web_app + ports: + - "5000:5000" + environment: + - DATABASE_URL=postgresql://flaskuser:password@db:5432/flaskdb + - FLASK_APP=app.py # Ensure Flask app is specified + - FLASK_ENV=development + command: flask run --host=0.0.0.0 # Ensure Flask runs with the correct host + depends_on: + - db + + db: + image: postgres:13 + container_name: flask_db + environment: + POSTGRES_DB: flaskdb + POSTGRES_USER: flaskuser + POSTGRES_PASSWORD: password + ports: + - "5432:5432" diff --git a/flask_postgresql_app/keploy.yml b/flask_postgresql_app/keploy.yml new file mode 100755 index 0000000..4a2a998 --- /dev/null +++ b/flask_postgresql_app/keploy.yml @@ -0,0 +1,61 @@ +path: "" +appId: 0 +appName: flask_postgresql_app +command: docker compose up --build +templatize: + testSets: [] +port: 0 +dnsPort: 26789 +proxyPort: 16789 +debug: false +disableTele: false +disableANSI: false +containerName: flask_postgresql_app +networkName: "" +buildDelay: 30 +test: + selectedTests: {} + globalNoise: + global: {} + test-sets: {} + delay: 5 + host: "" + port: 0 + apiTimeout: 5 + skipCoverage: false + coverageReportPath: "" + ignoreOrdering: true + mongoPassword: default@123 + language: "" + removeUnusedMocks: false + fallBackOnMiss: false + jacocoAgentPath: "" + basePath: "" + mocking: true + ignoredTests: {} + disableLineCoverage: false + disableMockUpload: true + useLocalMock: false + updateTemplate: false +record: + filters: [] + recordTimer: 0s +configPath: "" +bypassRules: [] +generateGithubActions: false +keployContainer: keploy-v2 +keployNetwork: keploy-network +cmdType: native +contract: + services: [] + tests: [] + path: "" + download: false + generate: false + driven: consumer + mappings: + servicesMapping: {} + self: "" +inCi: false + +# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file. diff --git a/flask_postgresql_app/keploy/.gitignore b/flask_postgresql_app/keploy/.gitignore new file mode 100644 index 0000000..5137843 --- /dev/null +++ b/flask_postgresql_app/keploy/.gitignore @@ -0,0 +1,2 @@ + +/reports/ diff --git a/flask_postgresql_app/keploy/test-set-0/mocks.yaml b/flask_postgresql_app/keploy/test-set-0/mocks.yaml new file mode 100755 index 0000000..2fb48be --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/mocks.yaml @@ -0,0 +1,1246 @@ +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-0 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.830573028Z + restimestampmock: 2024-10-09T16:52:02.831244867Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-1 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAKQADAAB1c2VyAGZsYXNrdXNlcgBkYXRhYmFzZQBmbGFza2RiAAA= + auth_type: 0 + postgresresponses: + - header: [R] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [133, 3, 221, 191] + msg_type: 82 + auth_type: 5 + reqtimestampmock: 2024-10-09T16:52:02.831996616Z + restimestampmock: 2024-10-09T16:52:02.832039452Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-2 +spec: + metadata: + type: config + postgresrequests: + - header: [p] + identifier: ClientRequest + length: 8 + password_message: + password: md5e9ccf75670af20adf7c4e48379bb8588 + msg_type: 112 + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 34 + secret_key: 2476999767 + parameter_status: + - name: application_name + value: "" + - name: client_encoding + value: UTF8 + - name: DateStyle + value: ISO, MDY + - name: integer_datetimes + value: "on" + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "on" + - name: server_encoding + value: UTF8 + - name: server_version + value: 13.16 (Debian 13.16-1.pgdg120+1) + - name: session_authorization + value: flaskuser + - name: standard_conforming_strings + value: "on" + - name: TimeZone + value: Etc/UTC + - name: TimeZone + value: Etc/UTC + - name: TimeZone + value: Etc/UTC + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.835642375Z + restimestampmock: 2024-10-09T16:52:02.835723939Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-3 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.836164161Z + restimestampmock: 2024-10-09T16:52:02.83619432Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-4 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAHdTRUxFQ1QgdC5vaWQsIHR5cGFycmF5CkZST00gcGdfdHlwZSB0IEpPSU4gcGdfbmFtZXNwYWNlIG5zCiAgICBPTiB0eXBuYW1lc3BhY2UgPSBucy5vaWQKV0hFUkUgdHlwbmFtZSA9ICdoc3RvcmUnOwoA + query: + string: 'SELECT t.oid, typarray FROM pg_type t JOIN pg_namespace ns ON typnamespace = ns.oid WHERE typname = ''hstore''; ' + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 0 + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: oid, table_oid: 1247, table_attribute_number: 1, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: typarray, table_oid: 1247, table_attribute_number: 14, data_type_oid: 26, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.837461213Z + restimestampmock: 2024-10-09T16:52:02.837501512Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-5 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: ROLLBACK + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.837848953Z + restimestampmock: 2024-10-09T16:52:02.837885486Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-6 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.838418843Z + restimestampmock: 2024-10-09T16:52:02.838454616Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-7 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select version() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: ['PostgreSQL 13.16 (Debian 13.16-1.pgdg120+1) on x86_64-pc-linux-gnu, compiled by gcc (Debian 12.2.0-14) 12.2.0, 64-bit']}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: version, table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.838665794Z + restimestampmock: 2024-10-09T16:52:02.838698521Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-8 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select current_schema() + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: [public]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: current_schema, table_oid: 0, table_attribute_number: 0, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.839613853Z + restimestampmock: 2024-10-09T16:52:02.839662169Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-9 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show transaction isolation level + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SHOW + data_row: [{row_values: [read committed]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: transaction_isolation, table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.83998089Z + restimestampmock: 2024-10-09T16:52:02.840014622Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-10 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT CAST('test plain returns' AS VARCHAR(60)) AS anon_1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: [test plain returns]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: anon_1, table_oid: 0, table_attribute_number: 0, data_type_oid: 1043, data_type_size: -1, type_modifier: 64, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.841477739Z + restimestampmock: 2024-10-09T16:52:02.84152715Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-11 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT CAST('test unicode returns' AS VARCHAR(60)) AS anon_1 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: [test unicode returns]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: anon_1, table_oid: 0, table_attribute_number: 0, data_type_oid: 1043, data_type_size: -1, type_modifier: 64, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.842010391Z + restimestampmock: 2024-10-09T16:52:02.84203208Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-12 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: show standard_conforming_strings + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SHOW + data_row: [{row_values: ["on"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: standard_conforming_strings, table_oid: 0, table_attribute_number: 0, data_type_oid: 25, data_type_size: -1, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.842246434Z + restimestampmock: 2024-10-09T16:52:02.842285151Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-13 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: ROLLBACK + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.842554536Z + restimestampmock: 2024-10-09T16:52:02.842597306Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-14 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.84341846Z + restimestampmock: 2024-10-09T16:52:02.84347898Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-15 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: select relname from pg_class c join pg_namespace n on n.oid=c.relnamespace where pg_catalog.pg_table_is_visible(c.oid) and relname='users' + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: [users]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: relname, table_oid: 1259, table_attribute_number: 2, data_type_oid: 19, data_type_size: 64, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.844216679Z + restimestampmock: 2024-10-09T16:52:02.844269317Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-16 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: ROLLBACK + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:02.844850035Z + restimestampmock: 2024-10-09T16:52:02.844879734Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-17 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:15.942120188Z + restimestampmock: 2024-10-09T16:52:15.942255625Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-18 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: INSERT INTO users (name) VALUES ('harshjoshi') RETURNING users.id + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: INSERT 0 1 + data_row: [{row_values: ["5"]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: id, table_oid: 16387, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:15.943656569Z + restimestampmock: 2024-10-09T16:52:15.943699019Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-19 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: COMMIT + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:15.948172194Z + restimestampmock: 2024-10-09T16:52:15.948306699Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-20 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:15.950999349Z + restimestampmock: 2024-10-09T16:52:15.951212649Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-21 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAFpTRUxFQ1QgdXNlcnMuaWQgQVMgdXNlcnNfaWQsIHVzZXJzLm5hbWUgQVMgdXNlcnNfbmFtZSAKRlJPTSB1c2VycyAKV0hFUkUgdXNlcnMuaWQgPSA1AA== + query: + string: SELECT users.id AS users_id, users.name AS users_name FROM users WHERE users.id = 5 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: ["5", harshjoshi]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: users_id, table_oid: 16387, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: users_name, table_oid: 16387, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: 84, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:15.960229809Z + restimestampmock: 2024-10-09T16:52:15.960468611Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-22 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: ROLLBACK + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:15.964142202Z + restimestampmock: 2024-10-09T16:52:15.964294111Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-23 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:24.27538668Z + restimestampmock: 2024-10-09T16:52:24.275522488Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-24 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAFpTRUxFQ1QgdXNlcnMuaWQgQVMgdXNlcnNfaWQsIHVzZXJzLm5hbWUgQVMgdXNlcnNfbmFtZSAKRlJPTSB1c2VycyAKV0hFUkUgdXNlcnMuaWQgPSA1AA== + query: + string: SELECT users.id AS users_id, users.name AS users_name FROM users WHERE users.id = 5 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: ["5", harshjoshi]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: users_id, table_oid: 16387, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: users_name, table_oid: 16387, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: 84, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:24.276356632Z + restimestampmock: 2024-10-09T16:52:24.276478637Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-25 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: UPDATE users SET name='harshjoshi1' WHERE users.id = 5 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: UPDATE 1 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:24.278842896Z + restimestampmock: 2024-10-09T16:52:24.278889652Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-26 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: COMMIT + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:24.281524213Z + restimestampmock: 2024-10-09T16:52:24.281569809Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-27 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:29.150281172Z + restimestampmock: 2024-10-09T16:52:29.150394831Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-28 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAFpTRUxFQ1QgdXNlcnMuaWQgQVMgdXNlcnNfaWQsIHVzZXJzLm5hbWUgQVMgdXNlcnNfbmFtZSAKRlJPTSB1c2VycyAKV0hFUkUgdXNlcnMuaWQgPSA1AA== + query: + string: SELECT users.id AS users_id, users.name AS users_name FROM users WHERE users.id = 5 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: ["5", harshjoshi1]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: users_id, table_oid: 16387, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: users_name, table_oid: 16387, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: 84, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:29.151126001Z + restimestampmock: 2024-10-09T16:52:29.151159414Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-29 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: DELETE FROM users WHERE users.id = 5 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: DELETE 1 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:29.152177132Z + restimestampmock: 2024-10-09T16:52:29.1522471Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-30 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: COMMIT + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:29.154192548Z + restimestampmock: 2024-10-09T16:52:29.154266201Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-31 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:34.320529598Z + restimestampmock: 2024-10-09T16:52:34.320605115Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-32 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAEZTRUxFQ1QgdXNlcnMuaWQgQVMgdXNlcnNfaWQsIHVzZXJzLm5hbWUgQVMgdXNlcnNfbmFtZSAKRlJPTSB1c2VycwA= + query: + string: SELECT users.id AS users_id, users.name AS users_name FROM users + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: ["4", harsh]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: users_id, table_oid: 16387, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: users_name, table_oid: 16387, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: 84, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:34.321330701Z + restimestampmock: 2024-10-09T16:52:34.321478797Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-33 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: ROLLBACK + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: ROLLBACK + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:34.323701768Z + restimestampmock: 2024-10-09T16:52:34.323826848Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-34 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:49.282145701Z + restimestampmock: 2024-10-09T16:52:49.282269829Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-35 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAFpTRUxFQ1QgdXNlcnMuaWQgQVMgdXNlcnNfaWQsIHVzZXJzLm5hbWUgQVMgdXNlcnNfbmFtZSAKRlJPTSB1c2VycyAKV0hFUkUgdXNlcnMuaWQgPSA0AA== + query: + string: SELECT users.id AS users_id, users.name AS users_name FROM users WHERE users.id = 4 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + data_row: [{row_values: ["4", harsh]}] + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: users_id, table_oid: 16387, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: users_name, table_oid: 16387, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: 84, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:49.282941176Z + restimestampmock: 2024-10-09T16:52:49.283010044Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-36 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: DELETE FROM users WHERE users.id = 4 + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: DELETE 1 + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:49.284580663Z + restimestampmock: 2024-10-09T16:52:49.284602152Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-37 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: COMMIT + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: COMMIT + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:49.286666457Z + restimestampmock: 2024-10-09T16:52:49.286736895Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-38 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: BEGIN + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: BEGIN + ready_for_query: + txstatus: 84 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:56.967044619Z + restimestampmock: 2024-10-09T16:52:56.967123063Z +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-39 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + payload: UQAAAEZTRUxFQ1QgdXNlcnMuaWQgQVMgdXNlcnNfaWQsIHVzZXJzLm5hbWUgQVMgdXNlcnNfbmFtZSAKRlJPTSB1c2VycwA= + query: + string: SELECT users.id AS users_id, users.name AS users_name FROM users + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 0 + ready_for_query: + txstatus: 84 + row_description: {fields: [{field_name: users_id, table_oid: 16387, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: users_name, table_oid: 16387, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: 84, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-10-09T16:52:56.96770962Z + restimestampmock: 2024-10-09T16:52:56.967773952Z +connectionId: "0" diff --git a/flask_postgresql_app/keploy/test-set-0/tests/test-1.yaml b/flask_postgresql_app/keploy/test-set-0/tests/test-1.yaml new file mode 100755 index 0000000..6e22f8a --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,53 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: close + Content-Length: "25" + Content-Type: application/json + Host: localhost:5000 + User-Agent: Thunder Client (https://www.thunderclient.com) + body: |- + { + "name":"harshjoshi" + } + timestamp: 2024-10-09T16:52:02.809644362Z + resp: + status_code: 200 + header: + Content-Length: "55" + Content-Type: application/json + Date: Wed, 09 Oct 2024 16:52:02 GMT + Server: Werkzeug/2.0.1 Python/3.9.20 + body: | + { + "message": "Welcome to the User Management API!" + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-09T16:52:04.856965925Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1728492724 +curl: |- + curl --request GET \ + --url http://localhost:5000/ \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Accept: */*' \ + --header 'User-Agent: Thunder Client (https://www.thunderclient.com)' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:5000' \ + --header 'Connection: close' \ + --data "{\n \"name\":\"harshjoshi\"\n}" diff --git a/flask_postgresql_app/keploy/test-set-0/tests/test-2.yaml b/flask_postgresql_app/keploy/test-set-0/tests/test-2.yaml new file mode 100755 index 0000000..ca56fc9 --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,50 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/users + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: close + Content-Length: "25" + Content-Type: application/json + Host: localhost:5000 + User-Agent: Thunder Client (https://www.thunderclient.com) + body: |- + { + "name":"harshjoshi" + } + timestamp: 2024-10-09T16:52:15.936436966Z + resp: + status_code: 201 + header: + Content-Length: "54" + Content-Type: application/json + Date: Wed, 09 Oct 2024 16:52:15 GMT + Server: Werkzeug/2.0.1 Python/3.9.20 + body: "{\n \"id\": 5, \n \"message\": \"User harshjoshi added.\"\n}\n" + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-09T16:52:18.022153619Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1728492738 +curl: |- + curl --request POST \ + --url http://localhost:5000/users \ + --header 'Accept: */*' \ + --header 'User-Agent: Thunder Client (https://www.thunderclient.com)' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:5000' \ + --header 'Connection: close' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --data "{\n \"name\":\"harshjoshi\"\n}" diff --git a/flask_postgresql_app/keploy/test-set-0/tests/test-3.yaml b/flask_postgresql_app/keploy/test-set-0/tests/test-3.yaml new file mode 100755 index 0000000..f99ce73 --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,53 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/users/5 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: close + Content-Length: "26" + Content-Type: application/json + Host: localhost:5000 + User-Agent: Thunder Client (https://www.thunderclient.com) + body: |- + { + "name":"harshjoshi1" + } + timestamp: 2024-10-09T16:52:24.271748853Z + resp: + status_code: 200 + header: + Content-Length: "35" + Content-Type: application/json + Date: Wed, 09 Oct 2024 16:52:24 GMT + Server: Werkzeug/2.0.1 Python/3.9.20 + body: | + { + "message": "User 5 updated." + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-09T16:52:26.3624278Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1728492746 +curl: |- + curl --request PUT \ + --url http://localhost:5000/users/5 \ + --header 'Connection: close' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Accept: */*' \ + --header 'User-Agent: Thunder Client (https://www.thunderclient.com)' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:5000' \ + --data "{\n \"name\":\"harshjoshi1\"\n}" diff --git a/flask_postgresql_app/keploy/test-set-0/tests/test-4.yaml b/flask_postgresql_app/keploy/test-set-0/tests/test-4.yaml new file mode 100755 index 0000000..36650b5 --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/tests/test-4.yaml @@ -0,0 +1,53 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-4 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/users/5 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: close + Content-Length: "26" + Content-Type: application/json + Host: localhost:5000 + User-Agent: Thunder Client (https://www.thunderclient.com) + body: |- + { + "name":"harshjoshi1" + } + timestamp: 2024-10-09T16:52:29.147040179Z + resp: + status_code: 200 + header: + Content-Length: "35" + Content-Type: application/json + Date: Wed, 09 Oct 2024 16:52:29 GMT + Server: Werkzeug/2.0.1 Python/3.9.20 + body: | + { + "message": "User 5 deleted." + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-09T16:52:31.185249908Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1728492751 +curl: |- + curl --request DELETE \ + --url http://localhost:5000/users/5 \ + --header 'Host: localhost:5000' \ + --header 'Connection: close' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Accept: */*' \ + --header 'User-Agent: Thunder Client (https://www.thunderclient.com)' \ + --header 'Content-Type: application/json' \ + --data "{\n \"name\":\"harshjoshi1\"\n}" diff --git a/flask_postgresql_app/keploy/test-set-0/tests/test-5.yaml b/flask_postgresql_app/keploy/test-set-0/tests/test-5.yaml new file mode 100755 index 0000000..97dab2a --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/tests/test-5.yaml @@ -0,0 +1,50 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-5 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/users + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: close + Content-Length: "26" + Content-Type: application/json + Host: localhost:5000 + User-Agent: Thunder Client (https://www.thunderclient.com) + body: |- + { + "name":"harshjoshi1" + } + timestamp: 2024-10-09T16:52:34.318334127Z + resp: + status_code: 200 + header: + Content-Length: "46" + Content-Type: application/json + Date: Wed, 09 Oct 2024 16:52:34 GMT + Server: Werkzeug/2.0.1 Python/3.9.20 + body: "[\n {\n \"id\": 4, \n \"name\": \"harsh\"\n }\n]\n" + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-09T16:52:36.413011311Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1728492756 +curl: |- + curl --request GET \ + --url http://localhost:5000/users \ + --header 'Accept: */*' \ + --header 'User-Agent: Thunder Client (https://www.thunderclient.com)' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:5000' \ + --header 'Connection: close' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --data "{\n \"name\":\"harshjoshi1\"\n}" diff --git a/flask_postgresql_app/keploy/test-set-0/tests/test-6.yaml b/flask_postgresql_app/keploy/test-set-0/tests/test-6.yaml new file mode 100755 index 0000000..649f206 --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/tests/test-6.yaml @@ -0,0 +1,53 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-6 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/users/4 + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: close + Content-Length: "26" + Content-Type: application/json + Host: localhost:5000 + User-Agent: Thunder Client (https://www.thunderclient.com) + body: |- + { + "name":"harshjoshi1" + } + timestamp: 2024-10-09T16:52:49.27966925Z + resp: + status_code: 200 + header: + Content-Length: "35" + Content-Type: application/json + Date: Wed, 09 Oct 2024 16:52:49 GMT + Server: Werkzeug/2.0.1 Python/3.9.20 + body: | + { + "message": "User 4 deleted." + } + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-09T16:52:51.378732252Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1728492771 +curl: |- + curl --request DELETE \ + --url http://localhost:5000/users/4 \ + --header 'User-Agent: Thunder Client (https://www.thunderclient.com)' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:5000' \ + --header 'Connection: close' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Accept: */*' \ + --data "{\n \"name\":\"harshjoshi1\"\n}" diff --git a/flask_postgresql_app/keploy/test-set-0/tests/test-7.yaml b/flask_postgresql_app/keploy/test-set-0/tests/test-7.yaml new file mode 100755 index 0000000..3aa1e77 --- /dev/null +++ b/flask_postgresql_app/keploy/test-set-0/tests/test-7.yaml @@ -0,0 +1,54 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-7 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:5000/users/ + header: + Accept: '*/*' + Accept-Encoding: gzip, deflate, br + Connection: close + Content-Length: "26" + Content-Type: application/json + Host: localhost:5000 + User-Agent: Thunder Client (https://www.thunderclient.com) + body: |- + { + "name":"harshjoshi1" + } + timestamp: 2024-10-09T16:52:53.793701467Z + resp: + status_code: 404 + header: + Content-Length: "232" + Content-Type: text/html; charset=utf-8 + Date: Wed, 09 Oct 2024 16:52:53 GMT + Server: Werkzeug/2.0.1 Python/3.9.20 + body: | + + 404 Not Found +

Not Found

+

The requested URL was not found on the server. If you entered the URL manually please check your spelling and try again.

+ status_message: Not Found + proto_major: 0 + proto_minor: 0 + timestamp: 2024-10-09T16:52:55.800973357Z + objects: [] + assertions: + noise: + header.Date: [] + created: 1728492775 +curl: |- + curl --request GET \ + --url http://localhost:5000/users/ \ + --header 'Host: localhost:5000' \ + --header 'Connection: close' \ + --header 'Accept-Encoding: gzip, deflate, br' \ + --header 'Accept: */*' \ + --header 'User-Agent: Thunder Client (https://www.thunderclient.com)' \ + --header 'Content-Type: application/json' \ + --data "{\n \"name\":\"harshjoshi1\"\n}" diff --git a/flask_postgresql_app/requirements.txt b/flask_postgresql_app/requirements.txt new file mode 100644 index 0000000..d6ff7bb --- /dev/null +++ b/flask_postgresql_app/requirements.txt @@ -0,0 +1,6 @@ +Flask==2.3.3 +Flask-SQLAlchemy==3.0.5 +psycopg2-binary==2.9.10 +Werkzeug==3.0.5 +SQLAlchemy==2.0.36 +python-dotenv From 28f4700c4ec2174ec7f804efa65af2ff58409746 Mon Sep 17 00:00:00 2001 From: Dhruv <136118444+slashexx@users.noreply.github.com> Date: Wed, 20 Nov 2024 18:53:08 +0530 Subject: [PATCH 25/31] Feat: Add sample sanic-postgres app for the samples python repository (#35) * Add sample postgres app Signed-off-by: slashexx * Add sanic app (keploy#2337) * Add readme Signed-off-by: slashexx --------- Signed-off-by: slashexx --- sanic-postgres/.env | 2 + sanic-postgres/.gitignore | 1 + sanic-postgres/README.md | 127 ++ sanic-postgres/keploy.yml | 61 + sanic-postgres/keploy/.gitignore | 2 + sanic-postgres/keploy/test-set-0/mocks.yaml | 1752 +++++++++++++++++ .../keploy/test-set-0/tests/test-1.yaml | 48 + .../keploy/test-set-0/tests/test-10.yaml | 37 + .../keploy/test-set-0/tests/test-11.yaml | 37 + .../keploy/test-set-0/tests/test-2.yaml | 48 + .../keploy/test-set-0/tests/test-3.yaml | 48 + .../keploy/test-set-0/tests/test-4.yaml | 48 + .../keploy/test-set-0/tests/test-5.yaml | 48 + .../keploy/test-set-0/tests/test-6.yaml | 37 + .../keploy/test-set-0/tests/test-7.yaml | 37 + .../keploy/test-set-0/tests/test-8.yaml | 38 + .../keploy/test-set-0/tests/test-9.yaml | 37 + sanic-postgres/requirements.txt | 43 + sanic-postgres/server.py | 123 ++ 19 files changed, 2574 insertions(+) create mode 100644 sanic-postgres/.env create mode 100644 sanic-postgres/.gitignore create mode 100644 sanic-postgres/README.md create mode 100755 sanic-postgres/keploy.yml create mode 100644 sanic-postgres/keploy/.gitignore create mode 100755 sanic-postgres/keploy/test-set-0/mocks.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-1.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-10.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-11.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-2.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-3.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-4.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-5.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-6.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-7.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-8.yaml create mode 100755 sanic-postgres/keploy/test-set-0/tests/test-9.yaml create mode 100644 sanic-postgres/requirements.txt create mode 100644 sanic-postgres/server.py diff --git a/sanic-postgres/.env b/sanic-postgres/.env new file mode 100644 index 0000000..151c5cd --- /dev/null +++ b/sanic-postgres/.env @@ -0,0 +1,2 @@ +FLASK_ENV=development +DATABASE_URL=postgresql://myuser:mypassword@localhost:5432/mydatabase diff --git a/sanic-postgres/.gitignore b/sanic-postgres/.gitignore new file mode 100644 index 0000000..43513b1 --- /dev/null +++ b/sanic-postgres/.gitignore @@ -0,0 +1 @@ +myenv/ \ No newline at end of file diff --git a/sanic-postgres/README.md b/sanic-postgres/README.md new file mode 100644 index 0000000..391b4c4 --- /dev/null +++ b/sanic-postgres/README.md @@ -0,0 +1,127 @@ +# Employee Management API + +This application is a simple employee management API built using Python's Sanic framework and PostgreSQL for data storage. It allows you to perform basic CRUD (Create, Read, Update, Delete) operations on employee records. + +## Table of Contents + +- [Introduction](#introduction) +- [Pre-Requisites](#pre-requisites) +- [Installation](#installation) +- [API Endpoints](#api-endpoints) + - [Create Employee](#create-employee) + - [Get All Employees](#get-all-employees) + - [Get Employee by ID](#get-employee-by-id) + - [Update Employee](#update-employee) + - [Delete Employee](#delete-employee) +- [Testing](#testing) +- [Wrapping it up](#wrapping-it-up) + +## Introduction + +🪄 Dive into the world of Employee Management and see how seamlessly Keploy integrated with Sanic and PostgreSQL. Buckle up, it's gonna be a fun ride! 🎢 + +## Pre-Requisites 🛠️ + +Before you begin, ensure you have the following installed: + +- **Python 3.x**: The programming language used for this application. You can download it from [python.org](https://www.python.org/downloads/). +- **PostgreSQL**: The database system used for storing employee data. You can download it from [postgresql.org](https://www.postgresql.org/download/). + +## Installation 📥 + +Once you have the prerequisites set up, follow these steps: + +1. Clone the repository: + + ```bash + git clone https://github.com/keploy/sample-python.git + cd sample-python +Install the required Python packages: + +```bash +pip install -r requirements.txt +``` + +Set up your PostgreSQL database and update the connection settings in your application as needed. + +Install the latest Keploy binary: + +```bash +curl --silent --location "https://github.com/keploy/keploy/releases/latest/download/keploy_linux_amd64.tar.gz" | tar xz -C /tmp +sudo mkdir -p /usr/local/bin && sudo mv /tmp/keploy /usr/local/bin && keploy +``` +Add alias for Keploy: + +```bash +alias keploy='sudo docker run --pull always --name keploy-v2 -p 16789:16789 --privileged --pid=host -it -v "$(pwd)":/files -v /sys/fs/cgroup:/sys/fs/cgroup -v /sys/kernel/debug:/sys/kernel/debug -v /sys/fs/bpf:/sys/fs/bpf -v /var/run/docker.sock:/var/run/docker.sock -v '"$HOME"'/.keploy-config:/root/.keploy-config -v '"$HOME"'/.keploy:/root/.keploy --rm ghcr.io/keploy/keploy' +``` +Install the dependencies: + +```bash +pip3 install -r requirements.txt +``` +API Endpoints +Create Employee +To add a new employee: + +```bash +curl -X POST http://localhost:8000/employees \ +-H "Content-Type: application/json" \ +-d '{ + "first_name": "John", + "last_name": "Doe", + "email": "john.doe@example.com", + "position": "Developer", + "salary": 60000 +}' +``` +Get All Employees +To retrieve all employees: + +```bash +curl -X GET http://localhost:8000/employees +``` + +Get Employee by ID +To retrieve a specific employee by ID: + +```bash +curl -X GET http://localhost:8000/employees/1 +``` +Update Employee +To update an existing employee's details: + +```bash +curl -X PUT http://localhost:8000/employees/1 \ +-H "Content-Type: application/json" \ +-d '{ + "first_name": "Jane", + "last_name": "Doe", + "email": "jane.doe@example.com", + "position": "Senior Developer", + "salary": 80000 +}' +``` +Delete Employee +To delete an employee: + +```bash +curl -X DELETE http://localhost:8000/employees/1 +``` +Testing +Capture Test Cases +Capture the test cases using Keploy: + +```bash +keploy record -c "python3 server.py" +``` +Run Tests +Run the tests: + +```bash +keploy test -c "python3 server.py" +``` +Wrapping it up 🎉 +Congrats on the journey so far! You've seen how to manage employees seamlessly with Keploy, Sanic, and PostgreSQL. Keep exploring, innovating, and creating! With the right tools, anything's possible. 😊🚀 + +Happy coding! ✨👩‍💻👨‍💻✨ \ No newline at end of file diff --git a/sanic-postgres/keploy.yml b/sanic-postgres/keploy.yml new file mode 100755 index 0000000..2e0604c --- /dev/null +++ b/sanic-postgres/keploy.yml @@ -0,0 +1,61 @@ +path: "" +appId: 0 +appName: sanic-postgres +command: python3 server.py +templatize: + testSets: [] +port: 0 +dnsPort: 26789 +proxyPort: 16789 +debug: false +disableTele: false +disableANSI: false +containerName: "" +networkName: "" +buildDelay: 30 +test: + selectedTests: {} + globalNoise: + global: {} + test-sets: {} + delay: 5 + host: "" + port: 0 + apiTimeout: 5 + skipCoverage: false + coverageReportPath: "" + ignoreOrdering: true + mongoPassword: default@123 + language: "" + removeUnusedMocks: false + fallBackOnMiss: false + jacocoAgentPath: "" + basePath: "" + mocking: true + ignoredTests: {} + disableLineCoverage: false + disableMockUpload: true + useLocalMock: false + updateTemplate: false +record: + filters: [] + recordTimer: 0s +configPath: "" +bypassRules: [] +generateGithubActions: false +keployContainer: keploy-v2 +keployNetwork: keploy-network +cmdType: native +contract: + services: [] + tests: [] + path: "" + download: false + generate: false + driven: consumer + mappings: + servicesMapping: {} + self: "" +inCi: false + +# Visit [https://keploy.io/docs/running-keploy/configuration-file/] to learn about using keploy through configration file. diff --git a/sanic-postgres/keploy/.gitignore b/sanic-postgres/keploy/.gitignore new file mode 100644 index 0000000..5137843 --- /dev/null +++ b/sanic-postgres/keploy/.gitignore @@ -0,0 +1,2 @@ + +/reports/ diff --git a/sanic-postgres/keploy/test-set-0/mocks.yaml b/sanic-postgres/keploy/test-set-0/mocks.yaml new file mode 100755 index 0000000..f6b10d5 --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/mocks.yaml @@ -0,0 +1,1752 @@ +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-0 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.083972836+05:30 + restimestampmock: 2024-11-02T00:24:00.084164389+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-1 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.167614021+05:30 + restimestampmock: 2024-11-02T00:24:00.17718867+05:30 +connectionId: "2" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-2 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.165411429+05:30 + restimestampmock: 2024-11-02T00:24:00.17710596+05:30 +connectionId: "4" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-3 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.177715308+05:30 + restimestampmock: 2024-11-02T00:24:00.18145664+05:30 +connectionId: "8" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-4 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.168265524+05:30 + restimestampmock: 2024-11-02T00:24:00.177743076+05:30 +connectionId: "6" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-5 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.177654462+05:30 + restimestampmock: 2024-11-02T00:24:00.199354838+05:30 +connectionId: "10" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-6 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.177594935+05:30 + restimestampmock: 2024-11-02T00:24:00.199162814+05:30 +connectionId: "12" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-7 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.198469406+05:30 + restimestampmock: 2024-11-02T00:24:00.234040088+05:30 +connectionId: "16" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-8 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.177518008+05:30 + restimestampmock: 2024-11-02T00:24:00.208708798+05:30 +connectionId: "14" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-9 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + length: 8 + payload: AAAACATSFi8= + ssl_request: + is_ssl: true + auth_type: 0 + postgresresponses: + - payload: Tg== + authentication_md5_password: + salt: [0, 0, 0, 0] + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.19854718+05:30 + restimestampmock: 2024-11-02T00:24:00.223360105+05:30 +connectionId: "18" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-10 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56033 + secret_key: 3037226085 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.103776338+05:30 + restimestampmock: 2024-11-02T00:24:00.103914002+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-11 +spec: + metadata: + type: config + postgresrequests: + - header: [P, D] + identifier: ClientRequest + length: 8 + payload: UAAAAHxfX2FzeW5jcGdfc3RtdF8xX18ASU5TRVJUIElOVE8gZW1wbG95ZWVzIChmaXJzdF9uYW1lLCBsYXN0X25hbWUsIGVtYWlsLCBwb3NpdGlvbiwgc2FsYXJ5KSBWQUxVRVMgKCQxLCAkMiwgJDMsICQ0LCAkNSkAAABEAAAAGFNfX2FzeW5jcGdfc3RtdF8xX18ASAAAAAQ= + describe: + object_type: 83 + name: __asyncpg_stmt_1__ + parse: + - name: __asyncpg_stmt_1__ + query: INSERT INTO employees (first_name, last_name, email, position, salary) VALUES ($1, $2, $3, $4, $5) + parameter_oids: [] + msg_type: 68 + auth_type: 0 + postgresresponses: + - header: ["1", t] + identifier: ServerResponse + length: 8 + payload: MQAAAAR0AAAAGgAFAAAEEwAABBMAAAQTAAAEEwAABqRuAAAABA== + authentication_md5_password: + salt: [0, 0, 0, 0] + parameter_description: + parameteroids: + - 1043 + - 1043 + - 1043 + - 1043 + - 1700 + msg_type: 116 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:11.553896163+05:30 + restimestampmock: 2024-11-02T00:24:11.554038629+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-12 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAAHoAX19hc3luY3BnX3N0bXRfMV9fAAAFAAEAAQABAAEAAQAFAAAAA0JvYgAAAAdKb2huc29uAAAAF2JvYi5qb2huc29uQGV4YW1wbGUuY29tAAAAD1Byb2plY3QgTWFuYWdlcgAAAAwAAgABAAAAAAAHE4gAAQABRQAAAAkAAAAAAFMAAAAE + bind: + - prepared_statement: __asyncpg_stmt_1__ + parameter_format_codes: [1, 1, 1, 1, 1] + parameters: [[66, 111, 98], [74, 111, 104, 110, 115, 111, 110], [98, 111, 98, 46, 106, 111, 104, 110, 115, 111, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [80, 114, 111, 106, 101, 99, 116, 32, 77, 97, 110, 97, 103, 101, 114], [0, 2, 0, 1, 0, 0, 0, 0, 0, 7, 19, 136]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: INSERT 0 1 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:11.580492915+05:30 + restimestampmock: 2024-11-02T00:24:11.581306226+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-13 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:11.586699965+05:30 + restimestampmock: 2024-11-02T00:24:11.588399417+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-14 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAAHsAX19hc3luY3BnX3N0bXRfMV9fAAAFAAEAAQABAAEAAQAFAAAAB0NoYXJsaWUAAAAFQnJvd24AAAAZY2hhcmxpZS5icm93bkBleGFtcGxlLmNvbQAAAAxEYXRhIEFuYWx5c3QAAAAMAAIAAQAAAAAABROIAAEAAUUAAAAJAAAAAABTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_1__ + parameter_format_codes: [1, 1, 1, 1, 1] + parameters: [[67, 104, 97, 114, 108, 105, 101], [66, 114, 111, 119, 110], [99, 104, 97, 114, 108, 105, 101, 46, 98, 114, 111, 119, 110, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [68, 97, 116, 97, 32, 65, 110, 97, 108, 121, 115, 116], [0, 2, 0, 1, 0, 0, 0, 0, 0, 5, 19, 136]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: INSERT 0 1 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:24.631061378+05:30 + restimestampmock: 2024-11-02T00:24:24.631153695+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-15 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:24.634474685+05:30 + restimestampmock: 2024-11-02T00:24:24.634607459+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-16 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAAHgAX19hc3luY3BnX3N0bXRfMV9fAAAFAAEAAQABAAEAAQAFAAAABURpYW5hAAAABlByaW5jZQAAABhkaWFuYS5wcmluY2VAZXhhbXBsZS5jb20AAAALVVggRGVzaWduZXIAAAAMAAIAAQAAAAAABwAAAAEAAUUAAAAJAAAAAABTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_1__ + parameter_format_codes: [1, 1, 1, 1, 1] + parameters: [[68, 105, 97, 110, 97], [80, 114, 105, 110, 99, 101], [100, 105, 97, 110, 97, 46, 112, 114, 105, 110, 99, 101, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [85, 88, 32, 68, 101, 115, 105, 103, 110, 101, 114], [0, 2, 0, 1, 0, 0, 0, 0, 0, 7, 0, 0]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: INSERT 0 1 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:34.337791555+05:30 + restimestampmock: 2024-11-02T00:24:34.337858813+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-17 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:34.341253861+05:30 + restimestampmock: 2024-11-02T00:24:34.341390263+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-18 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAAH4AX19hc3luY3BnX3N0bXRfMV9fAAAFAAEAAQABAAEAAQAFAAAABUV0aGFuAAAABEh1bnQAAAAWZXRoYW4uaHVudEBleGFtcGxlLmNvbQAAABVOZXR3b3JrIEFkbWluaXN0cmF0b3IAAAAMAAIAAQAAAAAABgAAAAEAAUUAAAAJAAAAAABTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_1__ + parameter_format_codes: [1, 1, 1, 1, 1] + parameters: [[69, 116, 104, 97, 110], [72, 117, 110, 116], [101, 116, 104, 97, 110, 46, 104, 117, 110, 116, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [78, 101, 116, 119, 111, 114, 107, 32, 65, 100, 109, 105, 110, 105, 115, 116, 114, 97, 116, 111, 114], [0, 2, 0, 1, 0, 0, 0, 0, 0, 6, 0, 0]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: INSERT 0 1 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:41.07876865+05:30 + restimestampmock: 2024-11-02T00:24:41.078836668+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-19 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:41.08021433+05:30 + restimestampmock: 2024-11-02T00:24:41.08029966+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-20 +spec: + metadata: + type: config + postgresrequests: + - header: [P, D] + identifier: ClientRequest + length: 8 + payload: UAAAAPZfX2FzeW5jcGdfc3RtdF8yX18ACiAgICAgICAgICAgIFVQREFURSBlbXBsb3llZXMKICAgICAgICAgICAgU0VUIGZpcnN0X25hbWUgPSAkMSwKICAgICAgICAgICAgICAgIGxhc3RfbmFtZSA9ICQyLAogICAgICAgICAgICAgICAgZW1haWwgPSAkMywKICAgICAgICAgICAgICAgIHBvc2l0aW9uID0gJDQsCiAgICAgICAgICAgICAgICBzYWxhcnkgPSAkNQogICAgICAgICAgICBXSEVSRSBpZCA9ICQ2CiAgICAgICAgICAgIAAAAEQAAAAYU19fYXN5bmNwZ19zdG10XzJfXwBIAAAABA== + describe: + object_type: 83 + name: __asyncpg_stmt_2__ + parse: + - name: __asyncpg_stmt_2__ + query: ' UPDATE employees SET first_name = $1, last_name = $2, email = $3, position = $4, salary = $5 WHERE id = $6 ' + parameter_oids: [] + msg_type: 68 + auth_type: 0 + postgresresponses: + - header: ["1", t] + identifier: ServerResponse + length: 8 + payload: MQAAAAR0AAAAHgAGAAAEEwAABBMAAAQTAAAEEwAABqQAAAAXbgAAAAQ= + authentication_md5_password: + salt: [0, 0, 0, 0] + parameter_description: + parameteroids: + - 1043 + - 1043 + - 1043 + - 1043 + - 1700 + - 23 + msg_type: 116 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:25:47.4085832+05:30 + restimestampmock: 2024-11-02T00:25:47.415893588+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-21 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAAIoAX19hc3luY3BnX3N0bXRfMl9fAAAGAAEAAQABAAEAAQABAAYAAAAFRnJhbmsAAAAGQ2FzdGxlAAAAGGZyYW5rLmNhc3RsZUBleGFtcGxlLmNvbQAAABNTZWN1cml0eSBTcGVjaWFsaXN0AAAADAACAAEAAAAAAAgAAAAAAAQAAAABAAEAAUUAAAAJAAAAAABTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_2__ + parameter_format_codes: [1, 1, 1, 1, 1, 1] + parameters: [[70, 114, 97, 110, 107], [67, 97, 115, 116, 108, 101], [102, 114, 97, 110, 107, 46, 99, 97, 115, 116, 108, 101, 64, 101, 120, 97, 109, 112, 108, 101, 46, 99, 111, 109], [83, 101, 99, 117, 114, 105, 116, 121, 32, 83, 112, 101, 99, 105, 97, 108, 105, 115, 116], [0, 2, 0, 1, 0, 0, 0, 0, 0, 8, 0, 0], [0, 0, 0, 1]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: UPDATE 0 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:25:47.460065945+05:30 + restimestampmock: 2024-11-02T00:25:47.460193217+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-22 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:25:47.463869372+05:30 + restimestampmock: 2024-11-02T00:25:47.463997714+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-23 +spec: + metadata: + type: config + postgresrequests: + - header: [P, D] + identifier: ClientRequest + length: 8 + payload: UAAAAD9fX2FzeW5jcGdfc3RtdF8zX18AU0VMRUNUICogRlJPTSBlbXBsb3llZXMgV0hFUkUgaWQgPSAkMQAAAEQAAAAYU19fYXN5bmNwZ19zdG10XzNfXwBIAAAABA== + describe: + object_type: 83 + name: __asyncpg_stmt_3__ + parse: + - name: __asyncpg_stmt_3__ + query: SELECT * FROM employees WHERE id = $1 + parameter_oids: [] + msg_type: 68 + auth_type: 0 + postgresresponses: + - header: ["1", t, T] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + parameter_description: + parameteroids: + - 23 + row_description: {fields: [{field_name: id, table_oid: 16386, table_attribute_number: 1, data_type_oid: 23, data_type_size: 4, type_modifier: -1, format: 0}, {field_name: first_name, table_oid: 16386, table_attribute_number: 2, data_type_oid: 1043, data_type_size: -1, type_modifier: 54, format: 0}, {field_name: last_name, table_oid: 16386, table_attribute_number: 3, data_type_oid: 1043, data_type_size: -1, type_modifier: 54, format: 0}, {field_name: email, table_oid: 16386, table_attribute_number: 4, data_type_oid: 1043, data_type_size: -1, type_modifier: 104, format: 0}, {field_name: position, table_oid: 16386, table_attribute_number: 5, data_type_oid: 1043, data_type_size: -1, type_modifier: 54, format: 0}, {field_name: salary, table_oid: 16386, table_attribute_number: 6, data_type_oid: 1700, data_type_size: -1, type_modifier: 655366, format: 0}, {field_name: date_hired, table_oid: 16386, table_attribute_number: 7, data_type_oid: 1082, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 84 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:25:57.958411237+05:30 + restimestampmock: 2024-11-02T00:25:57.958479842+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-24 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAACoAX19hc3luY3BnX3N0bXRfM19fAAABAAEAAQAAAAQAAAABAAEAAUUAAAAJAAAAAAFTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_3__ + parameter_format_codes: [1] + parameters: [[0, 0, 0, 1]] + result_format_codes: [1] + execute: + - max_rows: 1 + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 0 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:25:57.964307531+05:30 + restimestampmock: 2024-11-02T00:25:57.964414402+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-25 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:25:57.967177613+05:30 + restimestampmock: 2024-11-02T00:25:57.967355116+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-26 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAACoAX19hc3luY3BnX3N0bXRfM19fAAABAAEAAQAAAAQAAAADAAEAAUUAAAAJAAAAAAFTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_3__ + parameter_format_codes: [1] + parameters: [[0, 0, 0, 3]] + result_format_codes: [1] + execute: + - max_rows: 1 + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 0 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:02.277859505+05:30 + restimestampmock: 2024-11-02T00:26:02.278156136+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-27 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:02.281179011+05:30 + restimestampmock: 2024-11-02T00:26:02.281388742+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-28 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAACoAX19hc3luY3BnX3N0bXRfM19fAAABAAEAAQAAAAQAAAACAAEAAUUAAAAJAAAAAAFTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_3__ + parameter_format_codes: [1] + parameters: [[0, 0, 0, 2]] + result_format_codes: [1] + execute: + - max_rows: 1 + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", D, s, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + data_row: [{row_values: ['b64:AAAAAg==', Dhruv, slashexx, slashexx@example.com, Developer, 'b64:AAEAAQAAAAIABg==', 'b64:AAAjbw==']}] + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:04.963927809+05:30 + restimestampmock: 2024-11-02T00:26:04.965198376+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-29 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:04.970818229+05:30 + restimestampmock: 2024-11-02T00:26:04.971874274+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-30 +spec: + metadata: + type: config + postgresrequests: + - header: [P, D] + identifier: ClientRequest + length: 8 + payload: UAAAADtfX2FzeW5jcGdfc3RtdF80X18AREVMRVRFIEZST00gZW1wbG95ZWVzIFdIRVJFIGlkPSQxAAAARAAAABhTX19hc3luY3BnX3N0bXRfNF9fAEgAAAAE + describe: + object_type: 83 + name: __asyncpg_stmt_4__ + parse: + - name: __asyncpg_stmt_4__ + query: DELETE FROM employees WHERE id=$1 + parameter_oids: [] + msg_type: 68 + auth_type: 0 + postgresresponses: + - header: ["1", t] + identifier: ServerResponse + length: 8 + payload: MQAAAAR0AAAACgABAAAAF24AAAAE + authentication_md5_password: + salt: [0, 0, 0, 0] + parameter_description: + parameteroids: + - 23 + msg_type: 116 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:18.473156914+05:30 + restimestampmock: 2024-11-02T00:26:18.47327845+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-31 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAACoAX19hc3luY3BnX3N0bXRfNF9fAAABAAEAAQAAAAQAAAAFAAEAAUUAAAAJAAAAAABTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_4__ + parameter_format_codes: [1] + parameters: [[0, 0, 0, 5]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: DELETE 0 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:18.479261843+05:30 + restimestampmock: 2024-11-02T00:26:18.479381902+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-32 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:18.48461228+05:30 + restimestampmock: 2024-11-02T00:26:18.484716818+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-33 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAACoAX19hc3luY3BnX3N0bXRfNF9fAAABAAEAAQAAAAQAAAAIAAEAAUUAAAAJAAAAAABTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_4__ + parameter_format_codes: [1] + parameters: [[0, 0, 0, 8]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: DELETE 0 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:42.826314398+05:30 + restimestampmock: 2024-11-02T00:26:42.826364365+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-34 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:42.829870394+05:30 + restimestampmock: 2024-11-02T00:26:42.829976758+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-35 +spec: + metadata: + type: config + postgresrequests: + - header: [B, E] + identifier: ClientRequest + length: 8 + payload: QgAAACoAX19hc3luY3BnX3N0bXRfNF9fAAABAAEAAQAAAAQAAAACAAEAAUUAAAAJAAAAAABTAAAABA== + bind: + - prepared_statement: __asyncpg_stmt_4__ + parameter_format_codes: [1] + parameters: [[0, 0, 0, 2]] + result_format_codes: [1] + execute: + - {} + msg_type: 69 + auth_type: 0 + postgresresponses: + - header: ["2", C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: DELETE 1 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:45.439361257+05:30 + restimestampmock: 2024-11-02T00:26:45.439457915+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-36 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56036 + secret_key: 2072059547 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.198788779+05:30 + restimestampmock: 2024-11-02T00:24:00.206849467+05:30 +connectionId: "4" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-37 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56042 + secret_key: 1801189782 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.234047956+05:30 + restimestampmock: 2024-11-02T00:24:00.234128761+05:30 +connectionId: "10" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-38 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56043 + secret_key: 620349829 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.223511405+05:30 + restimestampmock: 2024-11-02T00:24:00.223563224+05:30 +connectionId: "12" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-39 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56044 + secret_key: 3570427540 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.246393386+05:30 + restimestampmock: 2024-11-02T00:24:00.246505351+05:30 +connectionId: "14" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-40 +spec: + metadata: + type: config + postgresrequests: + - header: [Q] + identifier: ClientRequest + length: 8 + query: + string: SELECT pg_advisory_unlock_all(); CLOSE ALL; UNLISTEN *; RESET ALL; + msg_type: 81 + auth_type: 0 + postgresresponses: + - header: [T, D, C, C, C, C, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + command_complete: + - command_tag_type: SELECT 1 + - command_tag_type: CLOSE CURSOR ALL + - command_tag_type: UNLISTEN + - command_tag_type: RESET + data_row: [{row_values: [""]}] + ready_for_query: + txstatus: 73 + row_description: {fields: [{field_name: pg_advisory_unlock_all, table_oid: 0, table_attribute_number: 0, data_type_oid: 2278, data_type_size: 4, type_modifier: -1, format: 0}]} + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:26:45.440448264+05:30 + restimestampmock: 2024-11-02T00:26:45.440621975+05:30 +connectionId: "0" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-41 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56046 + secret_key: 3378630764 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.254902613+05:30 + restimestampmock: 2024-11-02T00:24:00.255027369+05:30 +connectionId: "16" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-42 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56045 + secret_key: 3087317218 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.251125068+05:30 + restimestampmock: 2024-11-02T00:24:00.25123582+05:30 +connectionId: "18" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-43 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56037 + secret_key: 3109363849 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.22321499+05:30 + restimestampmock: 2024-11-02T00:24:00.223318321+05:30 +connectionId: "6" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-44 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56035 + secret_key: 3366720961 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.199235016+05:30 + restimestampmock: 2024-11-02T00:24:00.199320268+05:30 +connectionId: "2" +--- +version: api.keploy.io/v1beta1 +kind: Postgres +name: mock-45 +spec: + metadata: + type: config + postgresrequests: + - identifier: StartupRequest + payload: AAAAQQADAABjbGllbnRfZW5jb2RpbmcAJ3V0Zi04JwB1c2VyAG15dXNlcgBkYXRhYmFzZQBteWRhdGFiYXNlAAA= + auth_type: 0 + postgresresponses: + - header: [R, S, S, S, S, S, S, S, S, S, S, S, S, S, S, K, Z] + identifier: ServerResponse + length: 8 + authentication_md5_password: + salt: [0, 0, 0, 0] + backend_key_data: + process_id: 56038 + secret_key: 2167216798 + parameter_status: + - name: in_hot_standby + value: "off" + - name: integer_datetimes + value: "on" + - name: TimeZone + value: Asia/Kolkata + - name: IntervalStyle + value: postgres + - name: is_superuser + value: "off" + - name: application_name + value: "" + - name: default_transaction_read_only + value: "off" + - name: scram_iterations + value: "4096" + - name: DateStyle + value: ISO, MDY + - name: standard_conforming_strings + value: "on" + - name: session_authorization + value: myuser + - name: client_encoding + value: UTF8 + - name: server_version + value: "16.3" + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + - name: server_encoding + value: UTF8 + ready_for_query: + txstatus: 73 + msg_type: 90 + auth_type: 0 + reqtimestampmock: 2024-11-02T00:24:00.223405003+05:30 + restimestampmock: 2024-11-02T00:24:00.22346753+05:30 +connectionId: "8" diff --git a/sanic-postgres/keploy/test-set-0/tests/test-1.yaml b/sanic-postgres/keploy/test-set-0/tests/test-1.yaml new file mode 100755 index 0000000..cafa157 --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-1.yaml @@ -0,0 +1,48 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-1 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees + header: + Accept: '*/*' + Content-Length: "151" + Content-Type: application/json + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: |- + { + "first_name": "Bob", + "last_name": "Johnson", + "email": "bob.johnson@example.com", + "position": "Project Manager", + "salary": 75000 + } + timestamp: 2024-11-02T00:24:11.530933247+05:30 + resp: + status_code: 201 + header: + Connection: keep-alive + Content-Length: "27" + Content-Type: application/json + body: '{"status":"Employee added"}' + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:24:13.635103945+05:30 + objects: [] + assertions: + noise: {} + created: 1730487253 +curl: |- + curl --request POST \ + --url http://localhost:8000/employees \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data "{\n \"first_name\": \"Bob\",\n \"last_name\": \"Johnson\",\n \"email\": \"bob.johnson@example.com\",\n \"position\": \"Project Manager\",\n \"salary\": 75000\n}" diff --git a/sanic-postgres/keploy/test-set-0/tests/test-10.yaml b/sanic-postgres/keploy/test-set-0/tests/test-10.yaml new file mode 100755 index 0000000..72fe3cb --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-10.yaml @@ -0,0 +1,37 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-10 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees/8 + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: "" + timestamp: 2024-11-02T00:26:42.824245581+05:30 + resp: + status_code: 404 + header: + Connection: keep-alive + Content-Length: "31" + Content-Type: application/json + body: '{"status":"Employee not found"}' + status_message: Not Found + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:26:44.916426565+05:30 + objects: [] + assertions: + noise: {} + created: 1730487404 +curl: | + curl --request DELETE \ + --url http://localhost:8000/employees/8 \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ diff --git a/sanic-postgres/keploy/test-set-0/tests/test-11.yaml b/sanic-postgres/keploy/test-set-0/tests/test-11.yaml new file mode 100755 index 0000000..c601433 --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-11.yaml @@ -0,0 +1,37 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-11 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees/2 + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: "" + timestamp: 2024-11-02T00:26:45.433382637+05:30 + resp: + status_code: 200 + header: + Connection: keep-alive + Content-Length: "29" + Content-Type: application/json + body: '{"status":"Employee deleted"}' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:26:47.530880511+05:30 + objects: [] + assertions: + noise: {} + created: 1730487407 +curl: | + curl --request DELETE \ + --url http://localhost:8000/employees/2 \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ + --header 'Host: localhost:8000' \ diff --git a/sanic-postgres/keploy/test-set-0/tests/test-2.yaml b/sanic-postgres/keploy/test-set-0/tests/test-2.yaml new file mode 100755 index 0000000..6e02f3d --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-2.yaml @@ -0,0 +1,48 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-2 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees + header: + Accept: '*/*' + Content-Length: "152" + Content-Type: application/json + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: |- + { + "first_name": "Charlie", + "last_name": "Brown", + "email": "charlie.brown@example.com", + "position": "Data Analyst", + "salary": 55000 + } + timestamp: 2024-11-02T00:24:24.621246547+05:30 + resp: + status_code: 201 + header: + Connection: keep-alive + Content-Length: "27" + Content-Type: application/json + body: '{"status":"Employee added"}' + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:24:26.732572815+05:30 + objects: [] + assertions: + noise: {} + created: 1730487266 +curl: |- + curl --request POST \ + --url http://localhost:8000/employees \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/8.10.1' \ + --data "{\n \"first_name\": \"Charlie\",\n \"last_name\": \"Brown\",\n \"email\": \"charlie.brown@example.com\",\n \"position\": \"Data Analyst\",\n \"salary\": 55000\n}" diff --git a/sanic-postgres/keploy/test-set-0/tests/test-3.yaml b/sanic-postgres/keploy/test-set-0/tests/test-3.yaml new file mode 100755 index 0000000..be9e26f --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-3.yaml @@ -0,0 +1,48 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-3 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees + header: + Accept: '*/*' + Content-Length: "149" + Content-Type: application/json + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: |- + { + "first_name": "Diana", + "last_name": "Prince", + "email": "diana.prince@example.com", + "position": "UX Designer", + "salary": 70000 + } + timestamp: 2024-11-02T00:24:34.32675721+05:30 + resp: + status_code: 201 + header: + Connection: keep-alive + Content-Length: "27" + Content-Type: application/json + body: '{"status":"Employee added"}' + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:24:36.388946121+05:30 + objects: [] + assertions: + noise: {} + created: 1730487276 +curl: |- + curl --request POST \ + --url http://localhost:8000/employees \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:8000' \ + --data "{\n \"first_name\": \"Diana\",\n \"last_name\": \"Prince\",\n \"email\": \"diana.prince@example.com\",\n \"position\": \"UX Designer\",\n \"salary\": 70000\n}" diff --git a/sanic-postgres/keploy/test-set-0/tests/test-4.yaml b/sanic-postgres/keploy/test-set-0/tests/test-4.yaml new file mode 100755 index 0000000..90d4570 --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-4.yaml @@ -0,0 +1,48 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-4 +spec: + metadata: {} + req: + method: POST + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees + header: + Accept: '*/*' + Content-Length: "155" + Content-Type: application/json + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: |- + { + "first_name": "Ethan", + "last_name": "Hunt", + "email": "ethan.hunt@example.com", + "position": "Network Administrator", + "salary": 60000 + } + timestamp: 2024-11-02T00:24:41.068808434+05:30 + resp: + status_code: 201 + header: + Connection: keep-alive + Content-Length: "27" + Content-Type: application/json + body: '{"status":"Employee added"}' + status_message: Created + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:24:43.124788378+05:30 + objects: [] + assertions: + noise: {} + created: 1730487283 +curl: |- + curl --request POST \ + --url http://localhost:8000/employees \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --data "{\n \"first_name\": \"Ethan\",\n \"last_name\": \"Hunt\",\n \"email\": \"ethan.hunt@example.com\",\n \"position\": \"Network Administrator\",\n \"salary\": 60000\n}" diff --git a/sanic-postgres/keploy/test-set-0/tests/test-5.yaml b/sanic-postgres/keploy/test-set-0/tests/test-5.yaml new file mode 100755 index 0000000..441d38f --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-5.yaml @@ -0,0 +1,48 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-5 +spec: + metadata: {} + req: + method: PUT + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees/1 + header: + Accept: '*/*' + Content-Length: "157" + Content-Type: application/json + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: |- + { + "first_name": "Frank", + "last_name": "Castle", + "email": "frank.castle@example.com", + "position": "Security Specialist", + "salary": 80000 + } + timestamp: 2024-11-02T00:25:47.343116345+05:30 + resp: + status_code: 404 + header: + Connection: keep-alive + Content-Length: "31" + Content-Type: application/json + body: '{"status":"Employee not found"}' + status_message: Not Found + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:25:49.52236244+05:30 + objects: [] + assertions: + noise: {} + created: 1730487349 +curl: |- + curl --request PUT \ + --url http://localhost:8000/employees/1 \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ + --header 'Content-Type: application/json' \ + --header 'Host: localhost:8000' \ + --data "{\n \"first_name\": \"Frank\",\n \"last_name\": \"Castle\",\n \"email\": \"frank.castle@example.com\",\n \"position\": \"Security Specialist\",\n \"salary\": 80000\n}" diff --git a/sanic-postgres/keploy/test-set-0/tests/test-6.yaml b/sanic-postgres/keploy/test-set-0/tests/test-6.yaml new file mode 100755 index 0000000..acd2791 --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-6.yaml @@ -0,0 +1,37 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-6 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees/1 + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: "" + timestamp: 2024-11-02T00:25:57.955879435+05:30 + resp: + status_code: 404 + header: + Connection: keep-alive + Content-Length: "31" + Content-Type: application/json + body: '{"status":"Employee not found"}' + status_message: Not Found + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:25:59.977751505+05:30 + objects: [] + assertions: + noise: {} + created: 1730487359 +curl: | + curl --request GET \ + --url http://localhost:8000/employees/1 \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ diff --git a/sanic-postgres/keploy/test-set-0/tests/test-7.yaml b/sanic-postgres/keploy/test-set-0/tests/test-7.yaml new file mode 100755 index 0000000..3fff7c8 --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-7.yaml @@ -0,0 +1,37 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-7 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees/3 + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: "" + timestamp: 2024-11-02T00:26:02.274891841+05:30 + resp: + status_code: 404 + header: + Connection: keep-alive + Content-Length: "31" + Content-Type: application/json + body: '{"status":"Employee not found"}' + status_message: Not Found + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:26:04.302597857+05:30 + objects: [] + assertions: + noise: {} + created: 1730487364 +curl: | + curl --request GET \ + --url http://localhost:8000/employees/3 \ + --header 'Accept: */*' \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/8.10.1' \ diff --git a/sanic-postgres/keploy/test-set-0/tests/test-8.yaml b/sanic-postgres/keploy/test-set-0/tests/test-8.yaml new file mode 100755 index 0000000..7d23d7f --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-8.yaml @@ -0,0 +1,38 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-8 +spec: + metadata: {} + req: + method: GET + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees/2 + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: "" + timestamp: 2024-11-02T00:26:04.960388094+05:30 + resp: + status_code: 200 + header: + Connection: keep-alive + Content-Length: "162" + Content-Type: application/json + body: '{"employee":{"id":2,"first_name":"Dhruv","last_name":"slashexx","email":"slashexx@example.com","position":"Developer","salary":60000.0,"date_hired":"2024-11-01"}}' + status_message: OK + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:26:07.014944126+05:30 + objects: [] + assertions: + noise: + body.employee.date_hired: [] + created: 1730487367 +curl: | + curl --request GET \ + --url http://localhost:8000/employees/2 \ + --header 'Host: localhost:8000' \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ diff --git a/sanic-postgres/keploy/test-set-0/tests/test-9.yaml b/sanic-postgres/keploy/test-set-0/tests/test-9.yaml new file mode 100755 index 0000000..28f8605 --- /dev/null +++ b/sanic-postgres/keploy/test-set-0/tests/test-9.yaml @@ -0,0 +1,37 @@ +version: api.keploy.io/v1beta1 +kind: Http +name: test-9 +spec: + metadata: {} + req: + method: DELETE + proto_major: 1 + proto_minor: 1 + url: http://localhost:8000/employees/5 + header: + Accept: '*/*' + Host: localhost:8000 + User-Agent: curl/8.10.1 + body: "" + timestamp: 2024-11-02T00:26:18.470028007+05:30 + resp: + status_code: 404 + header: + Connection: keep-alive + Content-Length: "31" + Content-Type: application/json + body: '{"status":"Employee not found"}' + status_message: Not Found + proto_major: 0 + proto_minor: 0 + timestamp: 2024-11-02T00:26:20.586858053+05:30 + objects: [] + assertions: + noise: {} + created: 1730487380 +curl: | + curl --request DELETE \ + --url http://localhost:8000/employees/5 \ + --header 'User-Agent: curl/8.10.1' \ + --header 'Accept: */*' \ + --header 'Host: localhost:8000' \ diff --git a/sanic-postgres/requirements.txt b/sanic-postgres/requirements.txt new file mode 100644 index 0000000..7543908 --- /dev/null +++ b/sanic-postgres/requirements.txt @@ -0,0 +1,43 @@ +attrs==23.2.1.dev0 +autocommand==2.2.2 +beautifulsoup4==4.12.3 +cffi==1.16.0 +charset-normalizer==3.3.2 +configobj==5.0.8 +cryptography==42.0.7 +dbus-python==1.3.2 +fastjsonschema==2.20.0 +filelock==3.13.3 +httplib2==0.22.0 +idna==3.8 +jaraco.context==5.3.0 +jaraco.functools==4.0.2 +jaraco.text==4.0.0 +libtorrent==2.0.10 +lxml==5.3.0 +Mako==1.3.5.dev0 +Markdown==3.7 +MarkupSafe==2.1.5 +more-itertools==10.3.0 +ordered-set==4.1.0 +packaging==24.1 +pillow==10.4.0 +platformdirs==4.3.6 +pwquality==1.4.5 +pycairo==1.27.0 +pycparser==2.22 +pycurl==7.45.3 +PyGObject==3.50.0 +pyparsing==3.1.2 +Reflector==2023.6.28.0.36.1 +requests==2.32.3 +setuptools==69.5.1 +six==1.16.0 +soupsieve==2.6 +tomli==2.0.1 +trove-classifiers==2024.10.21.16 +urllib3==1.26.20 +validate==5.0.8 +validate-pyproject==0.21 +variety==0.8.12 +wheel==0.44.0 diff --git a/sanic-postgres/server.py b/sanic-postgres/server.py new file mode 100644 index 0000000..b28eb6f --- /dev/null +++ b/sanic-postgres/server.py @@ -0,0 +1,123 @@ +from sanic import Sanic, response +from asyncpg import create_pool +import os +from dotenv import load_dotenv + +app = Sanic("EmployeeManagementApp") + +load_dotenv() +DB_URL = os.getenv("DATABASE_URL") + +DB_CONFIG = { + "dsn": DB_URL, +} + +@app.listener("before_server_start") +async def setup_db(app, loop): + app.ctx.db_pool = await create_pool(**DB_CONFIG, loop=loop) + +@app.listener("after_server_stop") +async def close_db(app, loop): + await app.ctx.db_pool.close() + +@app.route("/employees", methods=["POST"]) +async def add_employee(request): + data = request.json + async with app.ctx.db_pool.acquire() as connection: + await connection.execute( + "INSERT INTO employees (first_name, last_name, email, position, salary) VALUES ($1, $2, $3, $4, $5)", + data["first_name"], data["last_name"], data["email"], data["position"], data["salary"] + ) + return response.json({"status": "Employee added"}, status=201) + +@app.route("/employees", methods=["GET"]) +async def get_employees(request): + async with app.ctx.db_pool.acquire() as connection: + rows = await connection.fetch("SELECT * FROM employees") + employees = [{"id": row["id"], "first_name": row["first_name"], "last_name": row["last_name"], + "email": row["email"], "position": row["position"], "salary": row["salary"], + "date_hired": row["date_hired"].isoformat()} for row in rows] + return response.json({"employees": employees}) + +@app.route("/employees/", methods=["GET"]) +async def get_employee(request, employee_id): + try: + employee_id = int(employee_id) + except ValueError: + return response.json({"status": "Invalid employee ID"}, status=400) + + async with app.ctx.db_pool.acquire() as connection: + row = await connection.fetchrow("SELECT * FROM employees WHERE id = $1", employee_id) + + if row is None: + return response.json({"status": "Employee not found"}, status=404) + + employee = { + "id": row["id"], + "first_name": row["first_name"], + "last_name": row["last_name"], + "email": row["email"], + "position": row["position"], + "salary": row["salary"], + "date_hired": row["date_hired"].isoformat() if row["date_hired"] else None + } + + return response.json({"employee": employee}) + +@app.route("/employees/", methods=["PUT"]) +async def update_employee(request, employee_id): + try: + employee_id = int(employee_id) + except ValueError: + return response.json({"status": "Invalid employee ID"}, status=400) + + updated_data = request.json + required_fields = ["first_name", "last_name", "email", "position", "salary"] + for field in required_fields: + if field not in updated_data: + return response.json({"status": f"Missing field: {field}"}, status=400) + + async with app.ctx.db_pool.acquire() as connection: + result = await connection.execute( + """ + UPDATE employees + SET first_name = $1, + last_name = $2, + email = $3, + position = $4, + salary = $5 + WHERE id = $6 + """, + updated_data["first_name"], + updated_data["last_name"], + updated_data["email"], + updated_data["position"], + float(updated_data["salary"]), + employee_id + ) + + if result == "UPDATE 0": + return response.json({"status": "Employee not found"}, status=404) + + return response.json({"status": "Employee updated"}) + +# Function to delete an employee +@app.route("/employees/", methods=["DELETE"]) +async def delete_employee(request, employee_id): + try: + employee_id = int(employee_id) + except ValueError: + return response.json({"status": "Invalid employee ID"}, status=400) + + async with app.ctx.db_pool.acquire() as connection: + result = await connection.execute( + "DELETE FROM employees WHERE id=$1", employee_id + ) + + if result == "DELETE 0": + return response.json({"status": "Employee not found"}, status=404) + + return response.json({"status": "Employee deleted"}) + +if __name__ == "__main__": + app.run(host="0.0.0.0", port=8000) From 20b388ec9c0038977b707999f2c48c7c1188d9b3 Mon Sep 17 00:00:00 2001 From: Khushi Trivedi <76205733+trivedi-khushi@users.noreply.github.com> Date: Tue, 31 Dec 2024 18:45:01 +0530 Subject: [PATCH 26/31] Bugfix/fastapi postgres (#34) * Added container name in docker-compose.yml Container name for database not given in this file. Thus, unable to start the application. * Updating changes in README.md When running natively on docker, changes need to be done in main.py & database.py from local host to container name. * Update README.md --- fastapi-postgres/README.md | 4 ++++ fastapi-postgres/docker-compose.yml | 3 ++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/fastapi-postgres/README.md b/fastapi-postgres/README.md index ebe959d..b1ccbf3 100644 --- a/fastapi-postgres/README.md +++ b/fastapi-postgres/README.md @@ -32,6 +32,10 @@ curl -O -L https:///keploy.io/install.sh && source install.sh docker-compose up -d ``` +> **Since we have setup our sample-app natively, we need to update the container name to postgres on line 6, in `application/database.py`, from `postgresql://postgres:postgres@localhost:5432/studentdb` to `postgresql://postgres:postgres@postgres:5432/studentdb`.** + +> **Also, we need to update the container name to postgres on line 11, of `application/main.py`, from `postgresql://postgres:postgres@localhost:5432/studentdb` to `postgresql://postgres:postgres@postgres:5432/studentdb`.** + ### Capture the Testcases This command will start the recording of API calls : diff --git a/fastapi-postgres/docker-compose.yml b/fastapi-postgres/docker-compose.yml index 80ec447..fd49830 100644 --- a/fastapi-postgres/docker-compose.yml +++ b/fastapi-postgres/docker-compose.yml @@ -3,6 +3,7 @@ services: postgres: image: postgres:latest + container_name: postgres environment: POSTGRES_DB: studentdb POSTGRES_USER: postgres @@ -30,4 +31,4 @@ services: networks: keploy-network: - external: true \ No newline at end of file + external: true From 48689586abf8cf64d40de0e282b6ecdef5f34d10 Mon Sep 17 00:00:00 2001 From: Animesh Pathak <53110238+Sonichigo@users.noreply.github.com> Date: Wed, 1 Jan 2025 13:19:11 +0800 Subject: [PATCH 27/31] fix: docker compose cmd (#37) --- fastapi-postgres/README.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/fastapi-postgres/README.md b/fastapi-postgres/README.md index b1ccbf3..56fd7e2 100644 --- a/fastapi-postgres/README.md +++ b/fastapi-postgres/README.md @@ -29,10 +29,10 @@ curl -O -L https:///keploy.io/install.sh && source install.sh ```bash # Start the application -docker-compose up -d +docker-compose up -d postgres ``` -> **Since we have setup our sample-app natively, we need to update the container name to postgres on line 6, in `application/database.py`, from `postgresql://postgres:postgres@localhost:5432/studentdb` to `postgresql://postgres:postgres@postgres:5432/studentdb`.** +> **If we have setup our sample-app with docker, we need to update the container name to postgres on line 6, in `application/database.py`, from `postgresql://postgres:postgres@localhost:5432/studentdb` to `postgresql://postgres:postgres@postgres:5432/studentdb`.** > **Also, we need to update the container name to postgres on line 11, of `application/main.py`, from `postgresql://postgres:postgres@localhost:5432/studentdb` to `postgresql://postgres:postgres@postgres:5432/studentdb`.** @@ -119,4 +119,3 @@ We will get output something like below - By making just 2 api call, we have generated a complete test suite for our application and acheived 72% coverage. So, no need to setup fake database/apis like Postgres or write mocks for them. Keploy automatically mocks them and, **The application thinks it's talking to Postgres 😄** - From 48036333ba0a80836fa473408fa444af7615545f Mon Sep 17 00:00:00 2001 From: Achanandhi M <110651321+Achanandhi-M@users.noreply.github.com> Date: Sun, 11 May 2025 18:45:10 +0530 Subject: [PATCH 28/31] chore: Update new slack url (#39) Signed-off-by: Achanandhi-M --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 55de833..f14f414 100644 --- a/README.md +++ b/README.md @@ -4,7 +4,7 @@
- + @@ -33,7 +33,7 @@ This repo contains the samples for [Keploy's](https://keploy.io) integration wit Reach out to us. We're here to help! -[![Slack](https://img.shields.io/badge/Slack-4A154B?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/keploy/shared_invite/zt-12rfbvc01-o54cOG0X1G6eVJTuI_orSA) +[![Slack](https://img.shields.io/badge/Slack-4A154B?style=for-the-badge&logo=slack&logoColor=white)](https://join.slack.com/t/keploy/shared_invite/zt-357qqm9b5-PbZRVu3Yt2rJIa6ofrwWNg) [![LinkedIn](https://img.shields.io/badge/linkedin-%230077B5.svg?style=for-the-badge&logo=linkedin&logoColor=white)](https://www.linkedin.com/company/keploy/) [![YouTube](https://img.shields.io/badge/YouTube-%23FF0000.svg?style=for-the-badge&logo=YouTube&logoColor=white)](https://www.youtube.com/channel/UC6OTg7F4o0WkmNtSoob34lg) [![Twitter](https://img.shields.io/badge/Twitter-%231DA1F2.svg?style=for-the-badge&logo=Twitter&logoColor=white)](https://twitter.com/Keployio) From c18373be0c52abf3e40c737fae4b2e0792b18d58 Mon Sep 17 00:00:00 2001 From: drishlekh Date: Thu, 19 Jun 2025 00:58:41 +0530 Subject: [PATCH 29/31] Added Twilio voice call feature using ngrok --- fastapi-twilio/.gitignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fastapi-twilio/.gitignore b/fastapi-twilio/.gitignore index bdd515a..04a54bd 100644 --- a/fastapi-twilio/.gitignore +++ b/fastapi-twilio/.gitignore @@ -1,2 +1,2 @@ ./venv -./__pycache__ \ No newline at end of file +./__pycache__.env From 09b34fab820d70a4f0a37560e2151a76955d980f Mon Sep 17 00:00:00 2001 From: drishlekh Date: Thu, 19 Jun 2025 01:08:13 +0530 Subject: [PATCH 30/31] Added Twilio voice call feature using ngrok --- fastapi-twilio/main.py | 74 +++++++++++++++++++++++++++++++++--------- 1 file changed, 59 insertions(+), 15 deletions(-) diff --git a/fastapi-twilio/main.py b/fastapi-twilio/main.py index 4cbb40c..8cd339a 100644 --- a/fastapi-twilio/main.py +++ b/fastapi-twilio/main.py @@ -1,45 +1,89 @@ -from fastapi import FastAPI +from fastapi import FastAPI, Request +from fastapi.responses import Response +from urllib.parse import quote import requests -from dotenv import load_dotenv from pydantic import BaseModel import os -import asyncio +from dotenv import load_dotenv # Load environment variables from a .env file load_dotenv() +app = FastAPI() class Message(BaseModel): Body: str To: str -app = FastAPI() - @app.post('/send-sms/') def send_sms(data: Message): twilio_account_sid = os.getenv('TWILIO_ACCOUNT_SID') twilio_auth_token = os.getenv('TWILIO_AUTH_TOKEN') twilio_phone_number = os.getenv('TWILIO_NUMBER') - url = f'https://api.twilio.com/2010-04-01/Accounts/{twilio_account_sid}/Messages.json' - payload = { 'Body': data.Body, 'From': twilio_phone_number, 'To': data.To } + response = requests.post(url=url, data=payload, auth=(twilio_account_sid, twilio_auth_token)) + if response.status_code == 201: + return {"message": "SMS sent successfully!"} + return {"message": "Failed to send SMS.", "details": response.text} + +@app.post("/make-call/") +def make_call(data: Message): + # Get Twilio credentials and your Twilio number from environment variables + account_sid = os.getenv('TWILIO_ACCOUNT_SID') + auth_token = os.getenv('TWILIO_AUTH_TOKEN') + twilio_number = os.getenv('TWILIO_NUMBER') + + # Get your public ngrok URL from environment variables (should be set manually) + ngrok_url = os.getenv('NGROK_URL') + + # Create a voice URL with the message as a query param (Twilio will fetch this) + voice_url = f"{ngrok_url}/voice?message={quote(data.Body)}" + + # Twilio's API endpoint to initiate a voice call + url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Calls.json" + + # Set up the details of the call: who to call, from which number, and what to say + payload = { + 'To': data.To, # The number to call + 'From': twilio_number, # Your Twilio number + 'Url': voice_url # Twilio fetches this to know what to speak + } + + # Make a POST request to Twilio to start the call + response = requests.post(url, data=payload, auth=(account_sid, auth_token)) + + # Check if the call was successfully created + if response.status_code == 201: + return {"message": "Call initiated successfully!"} + return {"message": "Failed to make the call.", "details": response.text} + + +@app.api_route("/voice", methods=["GET", "POST"]) +async def voice(request: Request): + # Extract the 'message' query parameter from the URL, or use a default + message = request.query_params.get("message", "Hello from Twilio!") + + # Print the message to the console for debugging/logging + print(f"📞 Twilio is trying to say: {message}") + + # Respond with TwiML (Twilio Markup Language) to tell Twilio what to speak + response = f""" + + {message} +""" + - try: - response = requests.post(url=url, data=payload, auth=(twilio_account_sid, twilio_auth_token)) - if response.status_code == 201: - return {"message": "SMS sent successfully!"} - else: - return {"message": "Failed to send SMS. Please check the provided phone number."} - except Exception as e: - return {"message": str(e)} + return Response(content=response, media_type="application/xml") + # Graceful shutdown @app.on_event("shutdown") async def shutdown_event(): print("Shutting down gracefully...") + # Perform any additional cleanup here if needed # For example, closing database connections or other resources \ No newline at end of file From 71faedaf09974af3df8f751fa31fa39ea8fb319b Mon Sep 17 00:00:00 2001 From: drishlekh <111127719+drishlekh@users.noreply.github.com> Date: Thu, 19 Jun 2025 01:51:15 +0530 Subject: [PATCH 31/31] Added Twilio voice call feature using ngrok --- fastapi-twilio/main.py | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/fastapi-twilio/main.py b/fastapi-twilio/main.py index 8cd339a..3b410f7 100644 --- a/fastapi-twilio/main.py +++ b/fastapi-twilio/main.py @@ -32,25 +32,25 @@ def send_sms(data: Message): @app.post("/make-call/") def make_call(data: Message): - # Get Twilio credentials and your Twilio number from environment variables + # Getting Twilio credentials and Twilio number from environment variables account_sid = os.getenv('TWILIO_ACCOUNT_SID') auth_token = os.getenv('TWILIO_AUTH_TOKEN') twilio_number = os.getenv('TWILIO_NUMBER') - # Get your public ngrok URL from environment variables (should be set manually) + # Get public ngrok URL from environment variables ngrok_url = os.getenv('NGROK_URL') - # Create a voice URL with the message as a query param (Twilio will fetch this) + # Creating a voice URL with the message as a query param (Twilio will fetch this) voice_url = f"{ngrok_url}/voice?message={quote(data.Body)}" # Twilio's API endpoint to initiate a voice call url = f"https://api.twilio.com/2010-04-01/Accounts/{account_sid}/Calls.json" - # Set up the details of the call: who to call, from which number, and what to say + # Setting up the details of the call: whom to call, from which number, and what to say payload = { - 'To': data.To, # The number to call - 'From': twilio_number, # Your Twilio number - 'Url': voice_url # Twilio fetches this to know what to speak + 'To': data.To, + 'From': twilio_number, + 'Url': voice_url } # Make a POST request to Twilio to start the call @@ -64,10 +64,10 @@ def make_call(data: Message): @app.api_route("/voice", methods=["GET", "POST"]) async def voice(request: Request): - # Extract the 'message' query parameter from the URL, or use a default + # Extracting the 'message' query parameter from the URL, or use a default message = request.query_params.get("message", "Hello from Twilio!") - # Print the message to the console for debugging/logging + print(f"📞 Twilio is trying to say: {message}") # Respond with TwiML (Twilio Markup Language) to tell Twilio what to speak @@ -86,4 +86,4 @@ async def shutdown_event(): print("Shutting down gracefully...") # Perform any additional cleanup here if needed - # For example, closing database connections or other resources \ No newline at end of file + # For example, closing database connections or other resources

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%0A6Iez8dd_|q2FhN2 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