-
-
Notifications
You must be signed in to change notification settings - Fork 82
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Implement Feedback submission #558
Open
harsh3dev
wants to merge
52
commits into
OWASP:main
Choose a base branch
from
harsh3dev:feature
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
+1,014
−2,938
Open
Changes from 1 commit
Commits
Show all changes
52 commits
Select commit
Hold shift + click to select a range
3e7889c
backend
harsh3dev 523a1f7
update api
harsh3dev eb4adea
remove logging
harsh3dev 64f0eb8
integrate frontend
harsh3dev 900f497
fix override issue
harsh3dev bfc63dc
update app for feedback
harsh3dev 4921628
add frontend tests
harsh3dev dc27d25
add backend tests
harsh3dev 21c1e35
resolve conflict
harsh3dev f008ef3
add poetry file
harsh3dev 15f242f
update error
harsh3dev ce32827
Merge branch
harsh3dev 80331a4
update poetry
harsh3dev cf43d92
fix backend tests
harsh3dev 911f314
Merge branch 'main' into feature
harsh3dev 5738e4f
fix
harsh3dev 0b3996a
Merge branch 'feature' of https://github.com/harsh3dev/Nest into feature
harsh3dev e888187
update package.json
harsh3dev 1245417
Merge branch 'main' of https://github.com/OWASP/Nest into feature
harsh3dev 3678db4
resolve conflicts and change components to chakra ui
harsh3dev acf9cd2
update form
harsh3dev 6d727af
remove shadcn components
harsh3dev 4d8c455
fix
harsh3dev 2846e66
Update backend/apps/feedback/api/feedback.py
harsh3dev f4f14f3
update requested changes
harsh3dev 15a155b
tests
harsh3dev ed32542
Merge branch 'feature' of https://github.com/harsh3dev/Nest into feature
harsh3dev 3e65a27
changes
harsh3dev 268d57f
Merge branch 'main' of https://github.com/OWASP/Nest into feature
harsh3dev 8baac60
pre commit
harsh3dev b70185e
check
harsh3dev d2dae82
add package-lock.json
harsh3dev ebc35b7
update
harsh3dev 7ae97d3
fix test
harsh3dev 72e788b
Merge branch 'main' of https://github.com/OWASP/Nest into feature
harsh3dev 663e731
update
harsh3dev ce5db3a
Merge branch 'main' of https://github.com/OWASP/Nest into feature
harsh3dev 66e68fa
.
harsh3dev 1e23459
Merge branch 'main' of https://github.com/OWASP/Nest into feature
harsh3dev 93ba308
add poetry
harsh3dev c0eb02d
update placement and icon
harsh3dev fc77079
pre commit
harsh3dev bd10806
update component
harsh3dev 20b5060
Merge branch 'main' into feature
harsh3dev 740ddfa
fix format
harsh3dev c3db979
Merge branch 'main' of https://github.com/OWASP/Nest into feature
harsh3dev f49f08a
rename test file
harsh3dev 636a6ff
fix: enhance structuredClone to handle undefined values
harsh3dev 0360316
fix: improve structuredClone function formatting
harsh3dev 04213f1
Merge branch 'main' into feature
harsh3dev cfe1690
update poetry
harsh3dev 1978b89
Merge branch 'main' of https://github.com/OWASP/Nest into feature
harsh3dev File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
fix backend tests
commit cf43d92f3856515a9b407de27e041232a9793b22
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,64 +1,111 @@ | ||
import json | ||
from unittest.mock import patch | ||
import csv | ||
from datetime import datetime, timezone | ||
from io import StringIO | ||
from unittest.mock import Mock, patch | ||
|
||
from django.urls import reverse | ||
import botocore | ||
import pytest | ||
from django.conf import settings | ||
from rest_framework import status | ||
from rest_framework.test import APITestCase | ||
|
||
|
||
class FeedbackViewSetTests(APITestCase): | ||
def setUp(self): | ||
self.url = reverse("feedback-list") | ||
self.valid_payload = { | ||
"name": "John Doe", | ||
"email": "john.doe@example.com", | ||
"message": "This is a feedback message.", | ||
"is_anonymous": False, | ||
"is_nestbot": False, | ||
} | ||
self.invalid_payload = { | ||
"name": "", | ||
"email": "invalid-email", | ||
"message": "", | ||
"is_anonymous": False, | ||
"is_nestbot": False, | ||
} | ||
|
||
@patch("apps.feedback.api.feedback.FeedbackViewSet._get_s3_client") | ||
def test_create_feedback_valid_payload(self, mock_get_s3_client): | ||
mock_s3_client = mock_get_s3_client.return_value | ||
mock_s3_client.get_object.side_effect = mock_s3_client.exceptions.NoSuchKey | ||
|
||
response = self.client.post( | ||
self.url, data=json.dumps(self.valid_payload), content_type="application/json" | ||
|
||
from apps.feedback.api.feedback import FeedbackViewSet | ||
|
||
|
||
@pytest.fixture() | ||
def feedback_viewset(): | ||
return FeedbackViewSet() | ||
|
||
|
||
@pytest.fixture() | ||
def valid_feedback_data(): | ||
return { | ||
"name": "John Doe", | ||
"email": "john@example.com", | ||
"message": "Test feedback", | ||
"is_anonymous": False, | ||
"is_nestbot": False, | ||
} | ||
|
||
|
||
@pytest.fixture() | ||
def mock_s3_client(): | ||
with patch("boto3.client") as mock_client: | ||
# Create a mock NoSuchKey exception | ||
mock_client.return_value.exceptions.NoSuchKey = botocore.exceptions.ClientError( | ||
{"Error": {"Code": "NoSuchKey", "Message": "The specified key does not exist."}}, | ||
"GetObject", | ||
) | ||
yield mock_client.return_value | ||
|
||
|
||
class TestFeedbackViewSet: | ||
def test_create_success(self, feedback_viewset, valid_feedback_data, mock_s3_client): | ||
"""Test successful feedback submission.""" | ||
# Mock request | ||
request = Mock() | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Could you get rid of the excessive comments here? Thank you! |
||
request.data = valid_feedback_data | ||
|
||
# Mock S3 get_object response for existing file | ||
mock_s3_client.get_object.return_value = {"Body": Mock(read=lambda: b"")} | ||
|
||
# Execute | ||
response = feedback_viewset.create(request) | ||
|
||
# Verify response | ||
assert response.status_code == status.HTTP_201_CREATED | ||
mock_get_s3_client.assert_called_once() | ||
|
||
# Verify S3 interactions | ||
mock_s3_client.put_object.assert_called_once() | ||
put_call_kwargs = mock_s3_client.put_object.call_args[1] | ||
assert put_call_kwargs["Bucket"] == settings.AWS_STORAGE_BUCKET_NAME | ||
assert put_call_kwargs["Key"] == "feedbacks.tsv" | ||
assert "Body" in put_call_kwargs | ||
assert put_call_kwargs["ContentType"] == "text/tab-separated-values" | ||
|
||
def test_create_validation_error(self, feedback_viewset, valid_feedback_data, mock_s3_client): | ||
"""Test feedback submission with validation error.""" | ||
# Mock request | ||
request = Mock() | ||
request.data = valid_feedback_data | ||
|
||
@patch("apps.feedback.api.feedback.FeedbackViewSet._get_s3_client") | ||
def test_create_feedback_invalid_payload(self, mock_get_s3_client): | ||
response = self.client.post( | ||
self.url, data=json.dumps(self.invalid_payload), content_type="application/json" | ||
# Mock S3 client to raise ValidationError using botocore exception | ||
mock_s3_client.get_object.side_effect = botocore.exceptions.ClientError( | ||
{"Error": {"Code": "ValidationError", "Message": "Invalid credentials"}}, "GetObject" | ||
) | ||
|
||
assert response.status_code == status.HTTP_400_BAD_REQUEST | ||
mock_get_s3_client.assert_not_called() | ||
# Execute | ||
response = feedback_viewset.create(request) | ||
|
||
@patch("apps.feedback.api.feedback.FeedbackViewSet._get_s3_client") | ||
def test_create_feedback_anonymous(self, mock_get_s3_client): | ||
payload = self.valid_payload.copy() | ||
payload["is_anonymous"] = True | ||
payload["email"] = "" | ||
# Verify response | ||
assert response.status_code == status.HTTP_201_CREATED | ||
|
||
mock_s3_client = mock_get_s3_client.return_value | ||
mock_s3_client.get_object.side_effect = mock_s3_client.exceptions.NoSuchKey | ||
def test_write_feedback_to_tsv(self, feedback_viewset, valid_feedback_data): | ||
"""Test writing feedback data to TSV format.""" | ||
output = StringIO() | ||
writer = csv.writer(output, delimiter="\t") | ||
|
||
response = self.client.post( | ||
self.url, data=json.dumps(payload), content_type="application/json" | ||
) | ||
# Execute | ||
current_time = datetime(2025, 1, 22, 10, 45, 34, 567884, tzinfo=timezone.utc) | ||
with patch("django.utils.timezone.now", return_value=current_time): | ||
feedback_viewset.write_feedback_to_tsv(writer, valid_feedback_data) | ||
|
||
assert response.status_code == status.HTTP_201_CREATED | ||
mock_get_s3_client.assert_called_once() | ||
mock_s3_client.put_object.assert_called_once() | ||
# Verify | ||
output.seek(0) | ||
written_data = output.getvalue().strip().split("\t") | ||
assert written_data[0] == valid_feedback_data["name"] | ||
assert written_data[1] == valid_feedback_data["email"] | ||
assert written_data[2] == valid_feedback_data["message"] | ||
assert written_data[3] == str(valid_feedback_data["is_anonymous"]) | ||
assert written_data[4] == str(valid_feedback_data["is_nestbot"]) | ||
|
||
@patch("boto3.client") | ||
def test_get_s3_client(self, mock_boto3, feedback_viewset): | ||
"""Test S3 client initialization.""" | ||
feedback_viewset.get_s3_client() | ||
|
||
mock_boto3.assert_called_once_with( | ||
"s3", | ||
aws_access_key_id=settings.AWS_ACCESS_KEY_ID, | ||
aws_secret_access_key=settings.AWS_SECRET_ACCESS_KEY, | ||
region_name=settings.AWS_S3_REGION_NAME, | ||
) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,14 +1,25 @@ | ||
from django.urls import resolve, reverse | ||
from rest_framework.test import SimpleTestCase | ||
import pytest | ||
|
||
from apps.feedback.api.feedback import FeedbackViewSet | ||
from apps.feedback.api.urls import router | ||
|
||
|
||
class FeedbackURLsTest(SimpleTestCase): | ||
def test_feedback_list_url_is_resolved(self): | ||
url = reverse("feedback-list") | ||
assert resolve(url).func.cls == FeedbackViewSet | ||
@pytest.mark.parametrize( | ||
("url_name", "expected_prefix", "viewset_class"), | ||
[ | ||
("feedback-list", "feedback", FeedbackViewSet), | ||
], | ||
) | ||
def test_router_registration(url_name, expected_prefix, viewset_class): | ||
matching_routes = [route for route in router.urls if route.name == url_name] | ||
assert matching_routes, f"Route '{url_name}' not found in router." | ||
|
||
def test_feedback_detail_url_is_resolved(self): | ||
url = reverse("feedback-detail", args=[1]) | ||
assert resolve(url).func.cls == FeedbackViewSet | ||
for route in matching_routes: | ||
assert ( | ||
expected_prefix in route.pattern.describe() | ||
), f"Prefix '{expected_prefix}' not found in route '{route.name}'." | ||
|
||
viewset = route.callback.cls | ||
assert issubclass( | ||
viewset, viewset_class | ||
), f"Viewset for '{route.name}' does not match {viewset_class}." |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What's going on here and can we make it a bit more readable please?