diff --git a/Makefile b/Makefile index 8b9a1f0..48ecfce 100644 --- a/Makefile +++ b/Makefile @@ -9,8 +9,9 @@ clean: rm -rf .coverage rm -rf report.xml rm -rf test.db + rm -rf htmlcov coverage: clean - pytest --cov=papi test_papi.py --junitxml=report.xml --cov-report=html --cov-report=xml --cov-report=term --cov-fail-under 90 + pytest --cov=papi --cov=posts --cov=users test_papi.py test_posts.py test_users.py --junitxml=report.xml --cov-report=html --cov-report=xml --cov-report=term --cov-fail-under 90 docker-img: coverage docker build -t ${DOCK_IMG} . docker-push: docker-img diff --git a/README.md b/README.md new file mode 100644 index 0000000..e69de29 diff --git a/db.py b/db.py new file mode 100644 index 0000000..e38624a --- /dev/null +++ b/db.py @@ -0,0 +1,20 @@ +from sqlalchemy import create_engine, Column, Integer,String, ForeignKey +from sqlalchemy.engine import URL +from sqlalchemy.orm import sessionmaker, Session, declarative_base + + +# Database setup +DATABASE_URL = "sqlite:///./test.db" +engine = create_engine(DATABASE_URL) +SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) +Base = declarative_base() + + + + +def get_db(): + db = SessionLocal() + try: + yield db + finally: + db.close() diff --git a/hopscotch_collection.json b/hopscotch_collection.json index 42c3ab5..a931533 100644 --- a/hopscotch_collection.json +++ b/hopscotch_collection.json @@ -1 +1,201 @@ -{"v":1,"name":"test_assignment","folders":[{"v":1,"name":"users","folders":[],"requests":[{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users","name":"list_users","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":null,"body":null}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users","name":"create_user","params":[],"headers":[],"method":"POST","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"test2\",\n \"email\":\"mynameisdeleted@gmail.com\",\n \"password\":\"pass2\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users/1","name":"update_user","params":[],"headers":[],"method":"PUT","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users/1","name":"delete_user","params":[],"headers":[],"method":"DELETE","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/users/1","name":"get_user","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":null,"body":null}}]},{"v":1,"name":"posts","folders":[],"requests":[{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts","name":"list_posts","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts","name":"create_post","params":[],"headers":[],"method":"POST","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"title\":\"test title\",\n \"content\":\"testing123\",\n \"author_id\":\"1\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts/1","name":"get_post","params":[],"headers":[],"method":"GET","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"name\":\"new name\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts/1","name":"update_post","params":[],"headers":[],"method":"PUT","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"title\":\"new title\"\n}"}},{"v":"1","endpoint":"https://papi.kube-dev.fairfaxmedia.net/posts/1","name":"delete_post","params":[],"headers":[],"method":"DELETE","auth":{"authType":"none","authActive":true},"preRequestScript":"","testScript":"","body":{"contentType":"application/json","body":"{\n \"title\":\"new title\"\n}"}}]}],"requests":[]} \ No newline at end of file +{ + "v": 1, + "name": "test_assignment", + "folders": [ + { + "v": 1, + "name": "users", + "folders": [], + "requests": [ + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/users", + "name": "list_users", + "params": [], + "headers": [], + "method": "GET", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": null, + "body": null + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/users", + "name": "create_user", + "params": [], + "headers": [], + "method": "POST", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"name\":\"test2\",\n \"email\":\"mynameisdeleted@gmail.com\",\n \"password\":\"pass2\"\n}" + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/users/1", + "name": "update_user", + "params": [], + "headers": [], + "method": "PUT", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"name\":\"new name\"\n}" + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/users/1", + "name": "delete_user", + "params": [], + "headers": [], + "method": "DELETE", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"name\":\"new name\"\n}" + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/users/1", + "name": "get_user", + "params": [], + "headers": [], + "method": "GET", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": null, + "body": null + } + } + ] + }, + { + "v": 1, + "name": "posts", + "folders": [], + "requests": [ + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/posts", + "name": "list_posts", + "params": [], + "headers": [], + "method": "GET", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"name\":\"new name\"\n}" + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/posts", + "name": "create_post", + "params": [], + "headers": [], + "method": "POST", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"title\":\"test title\",\n \"content\":\"testing123\",\n \"author_id\":\"1\"\n}" + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/posts/1", + "name": "get_post", + "params": [], + "headers": [], + "method": "GET", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"name\":\"new name\"\n}" + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/posts/1", + "name": "update_post", + "params": [], + "headers": [], + "method": "PUT", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"title\":\"new title\"\n}" + } + }, + { + "v": "1", + "endpoint": "https://papi.kube-dev.fairfaxmedia.net/posts/1", + "name": "delete_post", + "params": [], + "headers": [], + "method": "DELETE", + "auth": { + "authType": "none", + "authActive": true + }, + "preRequestScript": "", + "testScript": "", + "body": { + "contentType": "application/json", + "body": "{\n \"title\":\"new title\"\n}" + } + } + ] + } + ], + "requests": [] +} diff --git a/papi.py b/papi.py index 4925f3c..a35ac26 100644 --- a/papi.py +++ b/papi.py @@ -4,126 +4,21 @@ import uvicorn from sqlalchemy import create_engine, Column, Integer,String, ForeignKey from sqlalchemy.engine import URL from sqlalchemy.orm import sessionmaker, Session, declarative_base +import db +import users +import posts -# Database setup -DATABASE_URL = "sqlite:///./test.db" -engine = create_engine(DATABASE_URL) -SessionLocal = sessionmaker(autocommit=False, autoflush=False, bind=engine) -Base = declarative_base() - - -def get_db(): - db = SessionLocal() - try: - yield db - finally: - db.close() - - -class User(Base): - __tablename__ = "users" - id = Column(Integer, primary_key=True, index=True) - name = Column(String, index=True) - email = Column(String, unique=True, index=True) - password = Column(String) - - -class Post(Base): - __tablename__ = "posts" - id = Column(Integer, primary_key=True, index=True) - title = Column(String) - content = Column(String) - author_id = Column(Integer, ForeignKey("users.id")) - - - -Base.metadata.create_all(bind=engine) +db.Base.metadata.create_all(bind=db.engine) app = FastAPI() - +app.include_router(users.router) +app.include_router(posts.router) @app.get("/") async def root(): return {"message": "Hello World"} -@app.get("/users") -async def get_users(db: Session = Depends(get_db)): - return db.query(User).all() - -@app.get("/users/{id}") -async def get_user(id: str,db: Session = Depends(get_db)): - db_user = db.query(User).filter(User.id == id).first() - return db_user - -@app.post("/users") -async def create_user(user: dict,db: Session = Depends(get_db)): - #db_user = User(name=user["name"], email=user["email"], password=user["password"]) - db_user = User(**user) - db.add(db_user) - db.commit() - db.refresh(db_user) - return {"message":"User created successfully","user":db_user} - -@app.put("/users/{id}") -async def update_user(id: str, user: dict,db: Session = Depends(get_db)): - db_user = db.query(User).filter(User.id == id).first() - if "name" in user: - db_user.name = user["name"] - if "email" in user: - db_user.email = user["email"] - if "password" in user: - db_user.password = user["password"] - db.commit() - db.refresh(db_user) - return {"message":"User updated successfully","user":db_user} - - - -@app.delete("/users/{id}") -async def delete_user(id: str, db: Session = Depends(get_db)): - db_user = db.query(User).filter(User.id == id).first() - db.delete(db_user) - db.commit() - return {"message":"User deleted successfully","user":db_user} - - - -@app.get("/posts") -async def get_posts(db: Session = Depends(get_db)): - return db.query(Post).all() - -@app.get("/posts/{id}") -async def get_post(id: str,db: Session = Depends(get_db)): - return db.query(Post).filter(Post.id == id).first() - -@app.post("/posts") -async def create_post(post: dict,db: Session = Depends(get_db)): - db_post = Post(**post) - db.add(db_post) - db.commit() - db.refresh(db_post) - return {"message":"Post created successfully","post":db_post} - - -@app.put("/posts/{id}") -async def update_post(id: str, post: dict,db: Session = Depends(get_db)): - db_post = db.query(Post).filter(Post.id == id).first() - if "title" in post: - db_post.title = post["title"] - if "content" in post: - db_post.content = post["content"] - db.commit() - db.refresh(db_post) - return {"message":"Post updated successfully","post":db_post} - -@app.delete("/posts/{id}") -async def delete_post(id: str, db: Session = Depends(get_db)): - db_post = db.query(Post).filter(Post.id == id).first() - db.delete(db_post) - db.commit() - return {"message":"Post deleted successfully","post":db_post} - if __name__ == "__main__": diff --git a/posts.py b/posts.py new file mode 100644 index 0000000..b8941f7 --- /dev/null +++ b/posts.py @@ -0,0 +1,52 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import sessionmaker, Session, declarative_base +from sqlalchemy import create_engine, Column, Integer,String, ForeignKey + +import db + +class Post(db.Base): + __tablename__ = "posts" + id = Column(Integer, primary_key=True, index=True) + title = Column(String) + content = Column(String) + author_id = Column(Integer, ForeignKey("users.id")) + + +router = APIRouter(prefix="/posts") + +@router.get("") +def get_users(db: Session = Depends(db.get_db)): + return db.query(Post).all() + +@router.get("/{id}") +def get_user( id, db: Session = Depends(db.get_db)): + db_post = db.query(Post).filter(Post.id == id).first() + return db_post + +@router.post("") +def create_post( post: dict, db: Session = Depends(db.get_db)): + db_post = Post(**post) + db.add(db_post) + db.commit() + db.refresh(db_post) + return {"message":"Post created successfully","post":db_post} + +@router.put("/{id}") +def update_post( id, post: dict, db: Session = Depends(db.get_db)): + db_post = db.query(Post).filter(Post.id == id).first() + if "title" in post: + db_post.title = post["title"] + if "content" in post: + db_post.content = post["content"] + db.commit() + db.refresh(db_post) + return {"message":"Post updated successfully","post":db_post} + +@router.delete("/{id}") +def delete_post(id, db: Session = Depends(db.get_db)): + db_post = db.query(Post).filter(Post.id == id).first() + db.delete(db_post) + db.commit() + return {"message":"Post deleted successfully","post":db_post} + + diff --git a/test_papi.py b/test_papi.py index 3856a74..33e70e6 100644 --- a/test_papi.py +++ b/test_papi.py @@ -11,69 +11,4 @@ def test_read_main(): assert response.status_code == 200 assert response.json() == {"message": "Hello World"} -def test_read_users(): - response = client.get("/users") - assert response.status_code == 200 - assert response.json() == [] - -def test_create_read_delete_user(): - - response = client.post("/users",json={"name":"test","email":"mynameisdeleted@gmail.com","password":"pass2"}) - assert response.status_code == 200 - user=response.json()['user'] - user_id = str(user['id']) - response = client.get("/users/"+user_id) - assert response.status_code == 200 - assert response.json() == user - - update_response = client.put("/users/"+user_id,json={"name":"updated name"}) - #assert update_respose.status_code == 200 - put_user = update_response.json()['user'] - assert put_user['name'] == "updated name" - - update_response = client.put("/users/"+user_id,json={"email":"updated@gmail.com"}) - - put_user = update_response.json()['user'] - assert put_user['email'] == "updated@gmail.com" - - - response = client.delete("/users/"+user_id) - assert response.status_code == 200 - - response = client.get("/users") - assert response.status_code == 200 - assert response.json() == [] - - - - -def test_create_read_delete_post(): - - - response = client.post("/posts",json={"title":"test title","content":"testing123","author_id":"1"}) - assert response.status_code == 200 - post=response.json()['post'] - post_id = str(post['id']) - response = client.get("/posts/"+post_id) - assert response.status_code == 200 - assert response.json() == post - - update_response = client.put("/posts/"+post_id,json={"title":"test title updated"}) - #assert update_respose.status_code == 200 - put_post = update_response.json()['post'] - assert put_post['title'] == "test title updated" - - - update_response = client.put("/posts/"+post_id,json={"content":"updated content"}) - #assert update_respose.status_code == 200 - put_post = update_response.json()['post'] - assert put_post['title'] == "test title updated" - assert put_post['content'] == "updated content" - - response = client.delete("/posts/"+post_id) - assert response.status_code == 200 - - response = client.get("/posts") - assert response.status_code == 200 - assert response.json() == [] \ No newline at end of file diff --git a/test_posts.py b/test_posts.py new file mode 100644 index 0000000..fb3bd81 --- /dev/null +++ b/test_posts.py @@ -0,0 +1,51 @@ + + +from fastapi.testclient import TestClient + +from papi import app +client = TestClient(app) + +def test_read_post(): + response = client.get("/posts") + assert response.status_code == 200 + assert response.json() != None + +def test_create_post(): + response = client.post("/posts",json={"title":"test title","content":"testing123","author_id":"1"}) + assert response.status_code == 200 + post=response.json()['post'] + assert post['title'] == "test title" + assert post['content'] == "testing123" + assert post['author_id'] == 1 + client.delete("/posts/"+str(post['id'])) + + +def test_create_read_delete_post(): + first_posts = client.get("/posts").json() + + response = client.post("/posts",json={"title":"test title","content":"testing123","author_id":"1"}) + assert response.status_code == 200 + post=response.json()['post'] + post_id = str(post['id']) + response = client.get("/posts/"+post_id) + assert response.status_code == 200 + assert response.json() == post + + update_response = client.put("/posts/"+post_id,json={"title":"test title updated"}) + #assert update_respose.status_code == 200 + put_post = update_response.json()['post'] + assert put_post['title'] == "test title updated" + + + update_response = client.put("/posts/"+post_id,json={"content":"updated content"}) + #assert update_respose.status_code == 200 + put_post = update_response.json()['post'] + assert put_post['title'] == "test title updated" + assert put_post['content'] == "updated content" + + response = client.delete("/posts/"+post_id) + assert response.status_code == 200 + + response = client.get("/posts") + assert response.status_code == 200 + assert response.json() == first_posts \ No newline at end of file diff --git a/test_users.py b/test_users.py new file mode 100644 index 0000000..76e24b9 --- /dev/null +++ b/test_users.py @@ -0,0 +1,57 @@ + +from fastapi.testclient import TestClient + +from papi import app +client = TestClient(app) + +def test_read_user(): + response = client.get("/users") + assert response.status_code == 200 + assert response.json() != None + +def test_create_user(): + response = client.post("/users",json={"name":"test","email":"mynameisdeleted@gmail.com","password":"pass2"}) + assert response.status_code == 200 + user=response.json()['user'] + assert user['name'] == "test" + assert user['email'] == "mynameisdeleted@gmail.com" + assert user['password'] == "pass2" + client.delete("/users/"+str(user['id'])) + + +def test_create_read_delete_user(): + + response = client.post("/users",json={"name":"test","email":"mynameisdeleted@gmail.com","password":"pass2"}) + assert response.status_code == 200 + user=response.json()['user'] + user_id = str(user['id']) + response = client.get("/users/"+user_id) + assert response.status_code == 200 + assert response.json() == user + + update_response = client.put("/users/"+user_id,json={"name":"updated name"}) + #assert update_respose.status_code == 200 + put_user = update_response.json()['user'] + assert put_user['name'] == "updated name" + + update_response = client.put("/users/"+user_id,json={"email":"updated@gmail.com"}) + + put_user = update_response.json()['user'] + assert put_user['email'] == "updated@gmail.com" + assert put_user['name'] == "updated name" + + + update_response = client.put("/users/"+user_id,json={"password":"pw_updated"}) + + put_user = update_response.json()['user'] + assert put_user['password'] == "pw_updated" + assert put_user['email'] == "updated@gmail.com" + assert put_user['name'] == "updated name" + + + response = client.delete("/users/"+user_id) + assert response.status_code == 200 + + response = client.get("/users") + assert response.status_code == 200 + assert response.json() == [] diff --git a/users.py b/users.py new file mode 100644 index 0000000..e6b48b0 --- /dev/null +++ b/users.py @@ -0,0 +1,52 @@ +from fastapi import APIRouter, Depends +from sqlalchemy.orm import sessionmaker, Session, declarative_base +from sqlalchemy import create_engine, Column, Integer,String, ForeignKey + +import db + +class User(db.Base): + __tablename__ = "users" + id = Column(Integer, primary_key=True, index=True) + name = Column(String, index=True) + email = Column(String, unique=True, index=True) + password = Column(String) + + +router = APIRouter(prefix="/users") + +@router.get("") +def get_users(db: Session = Depends(db.get_db)): + return db.query(User).all() + +@router.get("/{id}") +def get_user( id, db: Session = Depends(db.get_db)): + db_user = db.query(User).filter(User.id == id).first() + return db_user + +@router.post("") +def create_user( user: dict, db: Session = Depends(db.get_db)): + db_user = User(**user) + db.add(db_user) + db.commit() + db.refresh(db_user) + return {"message":"User created successfully","user":db_user} + +@router.put("/{id}") +def update_user( id, user: dict, db: Session = Depends(db.get_db)): + db_user = db.query(User).filter(User.id == id).first() + if "name" in user: + db_user.name = user["name"] + if "email" in user: + db_user.email = user["email"] + if "password" in user: + db_user.password = user["password"] + db.commit() + db.refresh(db_user) + return {"message":"User updated successfully","user":db_user} + +@router.delete("/{id}") +def delete_user(id, db: Session = Depends(db.get_db)): + db_user = db.query(User).filter(User.id == id).first() + db.delete(db_user) + db.commit() + return {"message":"User deleted successfully","user":db_user}