Override settings in django tests - django

I try to:
#override_settings(EMAIL_HOST_PASSWORD='sdsds')
def test_email_not sent(self):
....
I want to brake down Django SMTP settings and test, but setting didn't get overrided.

By default, Django uses a local memory backend for emails when testing. See the docs for more info.
If you want to use the smtp backend, you can override the setting.
#override_settings(EMAIL_BACKEND='django.core.mail.backends.smtp.EmailBackend', EMAIL_HOST_PASSWORD='sdsds')
def test_email_not sent(self):
...

Related

How to connect Expo GO App to Django Rest Framework Backend on localhost?

I am implementing a react native application using Expo and testing it on my iOS device using Expo Go. I have a Django rest framework backend running on my local machine that I can access using my browser via http://localhost:8000 - using localhost in my react native app does not work during my fetch request. For instance:
let response = await fetch(BACKEND_URL + "/shft/auth/token/obtain/", {
method: "POST",
body: JSON.stringify(data),
headers: {
"Content-Type": "application/json",
},
});
returns
Network request failed
at node_modules\whatwg-fetch\dist\fetch.umd.js:null in setTimeout$argument_0
at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:null in _allocateCallback$argument_0
at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:null in _callTimer
at node_modules\react-native\Libraries\Core\Timers\JSTimers.js:null in callTimers
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in __callFunction
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in __guard$argument_0
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in __guard
at node_modules\react-native\Libraries\BatchedBridge\MessageQueue.js:null in callFunctionReturnFlushedQueue
I have tried setting BACKEND_URL to localhost:8000 and my public IP via expo-constants
import Constants from "expo-constants";
const { manifest } = Constants;
const uri = `http://${manifest.debuggerHost.split(":").shift()}:8000`;
But neither seems to work. I have enabled the Corsheaders middleware in my DRF project and placed the #csrf_exempt decorator on my APIView's dispatch method, and this error persists. I also added localhost:19000 to my CORS whitelist, which is where Expo seems to host its local server. What could be the problem here? Both the Expo server and the Django server are running locally on my laptop, and otherwise the API works in Django tests.
Using curl on my API endpoints via localhost also works, though the external IP returned by expo constants does not—but this may be because I am sending from localhost.
I found a fix using information from these two posts: this stack overflow and this blog. Neither of these solutions worked for me out of the box but a little networking logic makes it all come together. The core issue here is that the Django server is hosted locally but the Expo Go App is running on a separate mobile device (despite the expo server being hosted locally as well). I've tested each of the following steps to make sure they are all necessary.
Set up Django CORS using the corsheaders app and the corresponding middleware, there are guides on how to do this but basically pip install django-cors-headers then add it to your INSTALLED_APPS and Middleware in settings.py
INSTALLED_APPS = [
...,
'corsheaders',
]
# make sure CorsMiddleware comes before CommonMiddleware
MIDDLEWARE = [
...,
'corsheaders.middleware.CorsMiddleware',
'django.middleware.common.CommonMiddleware',
...,
]
Also use the #csrf_exempt decorator on the views you must be able to access (there are security implications to this but I am using JWT authentication anyways for this mobile app so this is okay in my case - I would do my due diligence here). There are a few ways to do this for function and class views:
from django.utils.decorators import method_decorator
from django.views.decorators.csrf import csrf_exempt
#csrf_exempt
def my_view():
...
# or for class based views
class my_view(APIView):
#csrf_exempt
def dispatch(self, request, *args, **kwargs):
return super().dispatch(self, request, *args, **kwargs)
# or my preferred way for easy copy paste
#method_decorator(csrf_exempt, name='dispatch')
class my_view(APIView):
...
Expose the Django server over LAN, this step is necessary so that your device can interface with the Django server over the local network - may not be necessary if using an emulator (though I'm aware that the Android emulator for instance accesses localhost using a specially designated IP address so I would check for this).
# specify this IP to expose on LAN
python manage.py runserver 0.0.0.0:8000
Find your local machine's IP address - the blog above uses the mobile device's IP but that did not work for me, which makes sense given that both servers are running on my laptop. For windows I opened the command prompt and entered ipconfig then found the IPv4...... line which contains my address.
Use this IP to direct your API calls and add it to your CORS whitelist. For example if your localmachine IP is 10.0.0.1 and Expo is on port 19000 while Django is on port 8000 we add the following.
# Django settings.py
ALLOWED_HOSTS = ['10.0.0.1',]
CORS_ORIGIN_WHITELIST = [
'http://10.0.0.1:19000',
]
// Wherever you define the backend URL for the frontend, in my case config.js
export const BACKEND_URL = "http://10.0.0.1:8000"
// Then make requests
fetch(BACKEND_URL + "/api/endpoint/", ...

How to insert Django data on Nginx logs?

Im thinking on how to retrieve Django user data on the user authetication class and pass it to Nginx session variables, then on the nginx logging settings use that data to create a Nginx access log entry that contains the Django user that create such a request.
I have found these ideas:
Get current request by Django's or Python threading
https://gist.github.com/vparitskiy/71bb97b4fd2c3fbd6d6db81546622346
https://nedbatchelder.com/blog/201008/global_django_requests.html
Set a session variable:
How can I set and get session variable in django?
And then log the cookie variable via a Nginx configuration like:
https://serverfault.com/questions/223584/how-to-add-recently-set-cookies-to-nginxs-access-log
https://serverfault.com/questions/872375/what-is-the-difference-between-http-cookie-and-cookie-name-in-nginx
Any better idea?. I'm reinventing the wheel?
Finally I have done this. Place a middleware en Django that insert in the cookies the logging data that I want nginx to log.
Then I used the $upstream_cookies_NAME to rescue the COOKIES['NAME'] if any.
have you read django's documentation on logging?
I haven't worked with nginx, yet, but with apache djangos default logger also outputs to the apache log, meaning that you can do this:
from logging import getLogger
logger = getLogger('django')
def my_view(request):
logger.info(f'my view: {request.user}')
which will output the user to the server log.

How to link Django and React URLs to perform actions?

In Django, I have my login URL set to 'api/auth/login'. When given a username and password, it will log that user in. Running 'python manage.py runserver', it will put that URL at 'http://127.0.0.1:8000/api/auth/login'
However, my React project, when running 'yarn start' is at 'http://localhost:3000/' and giving it the extension 'api/auth/login', the url it attempts is 'http://localhost:3000/api/auth/login'.
This does not work, but if I replace the URL extension with 'http://127.0.0.1:8000/api/auth/login', the login works as expected.
How can I have the URLs work with my React app? Or is this not something that necessarily needs to be fixed? I do plan to host this project somewhere and am not yet sure how the URLs will work out..
One option is to set proxy in the package.json.
Second option is to set axois baseURL:
// add in your code before main component definition
// for example in App.js
import axios from "axios";
axios.defaults.baseURL = "http://127.0.0.1:8000";
I'm preferring the second approach. For doing production build it can be easily overwritten with an environment variable.
import axios from "axios";
axios.defaults.baseURL = REACT_APP_SERVER_URL
Remember to set the CORS headers in the Django server (I'm working on tutorial with an example how to do this).
You are hosting react application on another port that's why when you put a request without mentioning host, it gets appended to your current host i.e. 127.0.0.1:3000. I suggest you write "proxy": '127. 0.0.1:8000' in your package.json (refer https://create-react-app.dev/docs/proxying-api-requests-in-development/) and restart your react server or use full url of django server i.e. 127.0.0.1:8000/

Use test database database for views testing

I am writing tests for my django application views and i am a beginner at this. I know that before running tests a new database is generated which only contains data that is being created at the time of running of tests but in my view's tests i am making API calls by url on my server which is using my default database not the test database in following way.
def test_decline_activity_valid_permission(self):
url = 'http://myapp:8002/api/v1/profile/' + self.profileUUID + '/document/' + \
self.docUUID + '/decline/'
response = requests.post(
url,
data=json.dumps(self.payload_valid_permission),
headers=self.headers,
)
self.assertEquals(response.status_code, status.HTTP_201_CREATED)
i want to know that if we can use test database for our testing our views or not. And what is difference between using request and using Client?
You could try using Django's LiveServerTestCase. That works like TransactionTestCase but will start up a server on localhost pointing at the test database. It gets started/stopped at the beginning/end of each test.
You could then configure the URL in your test to point at that local server. Django provides self.live_server_url for accessing the URL of the server.
As mentioned in the comments, Django's test client allows you to test views without making real HTTP requests. Whereas the requests library that you're using in your test, will send and receive real HTTP request and responses.

Unit testing with remote authentication

I have a suite of tests that I wrote while my app was using Django's default authentication, but now I've added Atlassian Crowd as the authentication method and those tests now fail, mainly because the Crowd server isn't there when I want to run my tests from home.
Each app has this in it's Setup() method
def setUp(self):
"""Set up the shared test data."""
self.client.login(username='admin', password='letmein')
I'm working around it at the moment by commenting out the AUTHENTICATION_BACKENDS, but that isn't going to work on the CI server.
I don't think the error I'm getting is important, but for completeness:
URLError: <urlopen error [Errno 8] nodename nor servname provided, or not known>
I've tried adding both auth backends into AUTHENTICATION_BACKENDS and I still get the same results.
What are my options for getting these tests to pass?
Is there any way to force the user to be logged in? Can I mock the auth object somehow?
Could I put some check around the AUTHENTICATION_BACKENDS section in setting to check if it's running in test mode? but then I'm writing special cases for my tests and that kind of defeats the object.
You could change the AUTHENTICATION_BACKENDS setting in the setUp method, then change it back in tearDown. This question's accepted answer has an example just that, but with a different setting.