unittest for custom errors - python

I have three different files:
A class file lang.py that has the following function
from errors import StatusCodeError
class LangModel:
def __init__(self, localpath2fst, host="127.0.0.1", port="5000", logfile="log"):
...
def state_update(self):
"""
Initialize the language model (on the server side)
"""
try:
r = requests.post(
'http://' +
self.host +
':' +
self.port +
'/init')
except requests.ConnectionError:
raise ConnectionErr(self.host, self.port)
if not r.status_code == requests.codes.ok:
raise StatusCodeError(r.status_code)
An error file errors.py:
class StatusCodeError(Exception):
def __init__(self, status_code):
self.dErrArgs = status_code
Exception.__init__(
self,
"Connection was not established and has status code {0}".format(self.dErrArgs))
and a third file test.py
import unittest
from lang import LangModel
from errors import StatusCodeError
class TestPreLM(unittest.TestCase):
def test_incorrect_input(self):
"""
confirm the process provides
an error given an incorrect
input
"""
abs_path_fst = os.path.abspath("a valid path")
# local fst
localfst = abs_path_fst
# init LMWrapper
lmodel = LangModel(
localfst,
host='127.0.0.1',
port='5000',
logfile="lmwrap.log")
# try to get priors
with self.assertRaises(StatusCodeError):
lmodel.state_update(['3'])
Oddly enough when I have the test code found within the class file, the test succeeds but when it is found in isolation (in test.py) the test fails and I'm unsure why. If you can lighten my way I'll be happy ;)

Related

Can i get the generated ip-address or domain name of flask_ngrok or py-ngrok and return it to 127.0.0.1/

I'm trying to get the generated domain name or IP-address of flask_ngrok or py-ngrok after been deploy. I want to deploy flask_app to localhost and get the new IP-address or domain name on the main page.
I.E: If I access 127.0.0.1/ I want it to return something like
You can now log in through https://aaf8447ee878.ngrok.io/
I have tried checking through the directories and read some help but I can't still get it. Thanks in advance ❤
add
import atexit
import json
import os
import platform
import shutil
import subprocess
import tempfile
import time
import zipfile
from pathlib import Path
from threading import Timer
import requests
def _run_ngrok():
ngrok_path = str(Path(tempfile.gettempdir(), "ngrok"))
_download_ngrok(ngrok_path)
system = platform.system()
if system == "Darwin":
command = "ngrok"
elif system == "Windows":
command = "ngrok.exe"
elif system == "Linux":
command = "ngrok"
else:
raise Exception(f"{system} is not supported")
executable = str(Path(ngrok_path, command))
os.chmod(executable, 777)
ngrok = subprocess.Popen([executable, 'http', '5000'])
atexit.register(ngrok.terminate)
localhost_url = "http://localhost:4040/api/tunnels" # Url with tunnel details
time.sleep(1)
tunnel_url = requests.get(localhost_url).text # Get the tunnel information
j = json.loads(tunnel_url)
tunnel_url = j['tunnels'][0]['public_url'] # Do the parsing of the get
tunnel_url = tunnel_url.replace("https", "http")
return tunnel_url
def _download_ngrok(ngrok_path):
if Path(ngrok_path).exists():
return
system = platform.system()
if system == "Darwin":
url = "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-darwin-amd64.zip"
elif system == "Windows":
url = "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-windows-amd64.zip"
elif system == "Linux":
url = "https://bin.equinox.io/c/4VmDzA7iaHb/ngrok-stable-linux-amd64.zip"
else:
raise Exception(f"{system} is not supported")
download_path = _download_file(url)
with zipfile.ZipFile(download_path, "r") as zip_ref:
zip_ref.extractall(ngrok_path)
def _download_file(url):
local_filename = url.split('/')[-1]
r = requests.get(url, stream=True)
download_path = str(Path(tempfile.gettempdir(), local_filename))
with open(download_path, 'wb') as f:
shutil.copyfileobj(r.raw, f)
return download_path
def start_ngrok():
global ngrok_address
ngrok_address = _run_ngrok()
print(f" * Running on {ngrok_address}")
print(f" * Traffic stats available on http://127.0.0.1:4040")
def run_with_ngrok(app):
"""
The provided Flask app will be securely exposed to the public internet via ngrok when run,
and the its ngrok address will be printed to stdout
:param app: a Flask application object
:return: None
"""
old_run = app.run
def new_run():
thread = Timer(1, start_ngrok)
thread.setDaemon(True)
thread.start()
old_run()
app.run = new_run
####################
dont import flask_ngrok
at the end at before name == 'main' add this function
def ngrok_url():
global tunnel_url
while True:
try:
print(ngrok_address)
except Exception as e:
print(e)
and after before app.run() put
thread = Timer(1, ngrok_url)
thread.setDaemon(True)
thread.start()
and run Warning: this will crash your code editor/ or terminal if u dont want that in the ngrok url function replace print with whatever you want to do with the url
and you dont need that
global tunnel_url
def ngrok_url():
while True:
try:
print(ngrok_address)
except Exception as e:
print(e)
you can delete the threading part before the name == 'main' too after the imports set
ngrok_address = ''
then you can accses the ngrok_address anywhere in your code
I found out the easiest way to do this is the just copy the url when the user is visiting the site. You can do this by...
#app.before_request
def before_request():
global url
url = request.url
# url = url.replace('http://', 'https://', 1)
url = url.split('.ngrok.io')[0]
url += '.ngrok.io'

Mocking gRPC status code ('RpcError' object has no attribute 'code') in Flask App

I have to create a unittest that should mock a specific grpc status code (in my case I need NOT_FOUND status).
This is what i want to mock:
try:
# my mocked function
except grpc.RpcError as e:
if e.code() == grpc.StatusCode.NOT_FOUND:
# do something
My unittest until now looks like this:
def mock_function_which_raise_RpcError():
e = grpc.RpcError(grpc.StatusCode.NOT_FOUND)
raise e
class MyTestCase(BaseViewTestCase):
#property
def base_url(self):
return '/myurl'
#mock.patch('my_func', mock_function_which_raise_RpcError)
def test_service_config_with_grpc_status_error(self):
# some code
assert resp.status_code == 404
First thing first, when I run my flask app and make a request to a URL with a specific body which should raise that RpcError, everything works just fine. e.code() is recognized. On the other hand, when i want to run that unittest, I get AttributeError: 'RpcError' object has no attribute 'code'.
Any thoughts?
Looks like you cannot construct a valid RpcError object from Python the same way it is created in the grpc code (which is written in C). You can, however, emulate the behavior by using:
def mock_function_which_raise_RpcError():
e = grpc.RpcError()
e.code = lambda: grpc.StatusCode.NOT_FOUND
raise e
Alternatively, you can derive your own exception:
class MyRpcError(grpc.RpcError):
def __init__(self, code):
self._code = code
def code(self):
return self._code
def mock_function_which_raise_RpcError():
raise MyRpcError(grpc.StatusCode.NOT_FOUND)
Update:
Added missing code method as mentioned by Martin Grůber in the comments.

Mocking ReviewBoard third party library using python and mock

I use ReviewBoard API library and today I moved the code to separate class and wanted to cover the logic with some tests. I understand mocks and testing but I am clearly not much experienced with the python and it's libraries. Here's the chunk of the real code:
<!-- language: python -->
from rbtools.api.client import RBClient
class ReviewBoardWrapper():
def __init__(self, url, username, password):
self.url = url
self.username = username
self.password = password
pass
def Connect(self):
self.client = RBClient(self.url, username=self.username, password=self.password)
self.root = self.client.get_root()
pass
And I want to assert the initialization as well as the get_root() methods are called. Here's how I try to accomplish that:
<!-- language: python -->
import unittest
import mock
from module_base import ReviewBoardWrapper as rb
class RbTestCase(unittest.TestCase):
#mock.patch('module_base.RBClient')
#mock.patch('module_base.RBClient.get_root')
def test_client_connect(self, mock_client, mock_method):
rb_client = rb('', '', '')
rb_client.Connect()
self.assertTrue(mock_method.called)
self.assertTrue(mock_client.called)
And here's the error I stuck on:
$ python -m unittest module_base_tests
F.
======================================================================
FAIL: test_client_connect (module_base_tests.RbTestCase)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/usr/local/lib/python2.7/dist-packages/mock/mock.py", line 1305, in patched
return func(*args, **keywargs)
File "module_base_tests.py", line 21, in test_client_connect
self.assertTrue(mock_client.called)
AssertionError: False is not true
----------------------------------------------------------------------
Ran 2 tests in 0.002s
FAILED (failures=1)
What do I do wrong? Do I correctly mock the "local copy" of imported libraries? Does the issue lie completely in a different area?
I have also tried to do this:
#mock.patch('module_base.RBClient.__init__')
And / or this:
self.assertTrue(mock_client.__init__.called)
In the example from your post, the order of the mocking is reversed:
test_client_connect(self, mock_client, mock_method)
The client is actually being mocked as the second argument and the method call is being mocked as the first argument.
However, to properly mock the client, you want to mock the return value of the client call. An example of mocking the return value and making an assertion on the return value would like the following:
class RbTestCase(unittest.TestCase):
#mock.patch('module_base.RBClient')
def test_client_connect(self, mock_client):
client = mock.MagicMock()
mock_client.return_value = client
rb_client = rb('', '', '')
rb_client.Connect()
self.assertTrue(client.get_root.called)
self.assertTrue(mock_client.called)

In this case, how can I write the queue.put

I'm writing a program to get the domain in same server and it also can scan the web directory.
#!/usr/bin/env python
#encoding = utf-8
import threading
import urllib,urllib2,httplib
from urllib2 import Request, urlopen, URLError
import Queue,sys
import re
concurrent = 5
url = sys.argv[1]
class Scanner(threading.Thread):
def __init__(self, work_q):
threading.Thread.__init__(self)
self.work_q = work_q
def getdomains(self):
doreq = Request('http://www.logontube.com/website/'+ url)
response = urlopen(doreq)
html = response.read()
response.close()
domains = re.findall('<br><a href=\"(.*?)\" target=\"_blank\"',html)
return domains
def run(self):
alldomains = self.getdomains()
pathline = [line.rstrip() for line in open("path.txt")]
while True:
for aim in alldomains:
for path in pathline:
path = self.work_q.get()
req = Request(aim+path)
try:
response = urlopen(req)
except URLError, e:
if hasattr(e, 'reason'):
print aim+path,'Not Found'
elif hasattr(e,'code'):
print aim+path,'Not Found'
else:
try:
logs = open('log.txt',"a+")
except(IOError):
print "[x] Failed to create log file"
print aim+path,"Found"
logs.writelines(aim+path+"\n")
logs.close()
def main():
work_q = Queue.Queue()
paths = [line.rstrip() for line in open("path.txt")]
for i in range(concurrent):
t = Scanner(work_q)
t.setDaemon(True)
t.start()
for path in paths:
work_q.put(path)
work_q.join()
main()
The problem is this program only do the loop of the path, so i only can get the scan result of one website.
I've found the problem,
for path in paths:
work_q.put(path) # The program finishes when it puts all the path
If you want to help me to test this program, you may need some directory of website(save it as path.txt)
/default.asp
/index.asp
/index.htm
/index.html
/index.jsp
/index.php
/admin.asp
/admin.php
/admin.shtml
/admin.txt
/admin_admin.asp
/config.asp
/inc/
/login.asp
/login.jsp
/login.php
/login/
/phpinfo.php
/readme.txt
/robots.txt
/test.asp
/test.html
/test.txt
/test.php
/news/readme.txt
/addmember/
You need a:
while 1:
pass
or something that waits until your threads are completed then it exits.
What is happening is that you are starting the threads but you are terminating the main thread so you never get to see the results of your threads.

unittest - Importerror

I'm following this tutorial on web2py where you get to make a testdriven environment. However when I try to run the test with unittest, selenium I get this error:
$ python functional_tests.py
running tests
Traceback (most recent call last):
File "functional_tests.py", line 56, in <module>
run_functional_tests()
File "functional_tests.py", line 46, in run_functional_tests
tests = unittest.defaultTestLoader.discover('fts')
File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/unittest/loader.py", line 202, in discover
raise ImportError('Start directory is not importable: %r' % start_dir)
ImportError: Start directory is not importable: 'fts'
This is how the functional_tests.py looks like:
#!/usr/bin/env python
try: import unittest2 as unittest #for Python <= 2.6
except: import unittest
import sys, urllib2
sys.path.append('./fts/lib')
from selenium import webdriver
import subprocess
import sys
import os.path
ROOT = 'http://localhost:8001'
class FunctionalTest(unittest.TestCase):
#classmethod
def setUpClass(self):
self.web2py = start_web2py_server()
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(1)
#classmethod
def tearDownClass(self):
self.browser.close()
self.web2py.kill()
def get_response_code(self, url):
"""Returns the response code of the given url
url the url to check for
return the response code of the given url
"""
handler = urllib2.urlopen(url)
return handler.getcode()
def start_web2py_server():
#noreload ensures single process
print os.path.curdir
return subprocess.Popen([
'python', '../../web2py.py', 'runserver', '-a "passwd"', '-p 8001'
])
def run_functional_tests(pattern=None):
print 'running tests'
if pattern is None:
tests = unittest.defaultTestLoader.discover('fts')
else:
pattern_with_globs = '*%s*' % (pattern,)
tests = unittest.defaultTestLoader.discover('fts', pattern=pattern_with_globs)
runner = unittest.TextTestRunner()
runner.run(tests)
if __name__ == '__main__':
if len(sys.argv) == 1:
run_functional_tests()
else:
run_functional_tests(pattern=sys.argv[1])
I solved this problem by replacing fts with the full path i.e. /home/simon/web2py/applications/testapp/fts
Hope this helps
I had the same problem and based on an excellent article unit testing with web2py,
I got this to work by doing the following:
Create a tests folder in the tukker directory
Copy/save the amended code(below) into tests folder as alt_functional_tests.py
Alter the web2py path in the start_web2py_server function to your own path
To run, enter the command: python web2py.py -S tukker -M -R applications/tukker/tests/alt_functional_tests.py
I am no expert but hopefully this will work for you also.
import unittest
from selenium import webdriver
import subprocess
import urllib2
execfile("applications/tukker/controllers/default.py", globals())
ROOT = 'http://localhost:8001'
def start_web2py_server():
return subprocess.Popen([
'python', '/home/alan/web2py/web2py/web2py.py', 'runserver',
'-a "passwd"', '-p 8001' ])
class FunctionalTest(unittest.TestCase):
#classmethod
def setUpClass(self):
self.web2py = start_web2py_server()
self.browser = webdriver.Firefox()
self.browser.implicitly_wait(1)
#classmethod
def tearDownClass(self):
self.browser.close()
self.web2py.kill()
def get_response_code(self, url):
"""Returns the response code of the given url
url the url to check for
return the response code of the given url
"""
handler = urllib2.urlopen(url)
return handler.getcode()
def test_can_view_home_page(self):
# John opens his browser and goes to the home-page of the tukker app
self.browser.get(ROOT + '/tukker/')
# He's looking at homepage and sees Heading "Messages With 300 Chars"
body = self.browser.find_element_by_tag_name('body')
self.assertIn('Messages With 300 Chars', body.text)
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(FunctionalTest))
unittest.TextTestRunner(verbosity=2).run(suite)
First you have to do some changes in wrong paths in fts/functional_tests.py
search for
'python', '../../web2py.py', 'runserver', '-a "passwd"', '-p 8001'
and change it to
'python', '../../../web2py.py', 'runserver', '-a "passwd"', '-p 8001'
then
tests = unittest.defaultTestLoader.discover('fts')
to
tests = unittest.defaultTestLoader.discover('.')
then
tests = unittest.defaultTestLoader.discover('fts', pattern=pattern_with_globs)
to
tests = unittest.defaultTestLoader.discover('.', pattern=pattern_with_globs)
and
sys.path.append('fts/lib')
to
sys.path.append('./lib')

Categories

Resources