def test_verify_nonprivileged_user_cannot_change_other_fields(self): ''' Verify that a non-privileged user cannot change their account aside from the password. ''' payload = {'format': 'json'} response = self.client.get(self.api_user_url, params=payload) # Create the user username, password = self.getUsernamePassword() response = self._create_user(username, password) user_uri = response.headers['location'] # Get a login session client = NMTKClient(self.site_url) response = client.login(username, password) user_data = client.get(user_uri).json() user_data['username'] = '******' # Just in case self.delusers.append('test_new_username') response = client.put(user_uri, data=json.dumps(user_data)) logger.debug(response.text) self.assertEqual( response.status_code, 401, 'Response to change username should be 400, not %s' % (response.status_code, ))
def test_verify_nonprivileged_user_cannot_change_other_fields(self): ''' Verify that a non-privileged user cannot change their account aside from the password. ''' payload={'format': 'json' } response=self.client.get(self.api_user_url, params=payload) # Create the user username, password=self.getUsernamePassword() response=self._create_user(username, password) user_uri=response.headers['location'] # Get a login session client=NMTKClient(self.site_url) response=client.login(username, password) user_data=client.get(user_uri).json() user_data['username']='******' # Just in case self.delusers.append('test_new_username') response=client.put(user_uri, data=json.dumps(user_data)) logger.debug(response.text) self.assertEqual(response.status_code, 401, 'Response to change username should be 400, not %s' % (response.status_code,))
def test_submit_job(self): ''' Verify that we can properly submit a job (form) via the API and \ get back the (eventual) results and status of the running job. Also ensure other \ users cannot download results. ''' username, password = self.getUsernamePassword() user_uri = self._create_user(username, password) client = NMTKClient(self.site_url) response = client.login(username=username, password=password) filename = self.get_support_file('test1.geojson') test_file = client.uploadData(filename, description='Test data file (MSP)') logger.debug('URI of test file is %s', test_file) tool_url = client.getURL('api', 'tool/') job_url = client.getURL('api', 'job/') response = client.get(tool_url, params={'format': 'json'}) tools = response.json()['objects'] # Get a list of all the Tool Resource URIs for Minnesota models, # since the test1.geojson file is a MN model-specific data file. for tool in tools: if 'umn' in tool['name'].lower(): tool_uri = tool['resource_uri'] break data = { 'tool': client.neuter_url(tool_uri), 'description': 'Test job for testing by the automated test!' } response = client.post(job_url, data=json.dumps(data), headers={ 'Content-Type': 'application/json', }) #logger.debug('Result from post was %s', response.text) self.assertEqual( response.status_code, 201, ('Expected job to be created - ' + 'got back %s instead') % (response.status_code, )) job_uri = response.headers['location'] # Now we have a job, let's get the form, generate the response, and # submit it back to the user. payload = { "config": { "coefficients": { "Arterial_coeff": { "type": "number", "value": 391.8 }, "BusRoute_coeff": { "type": "number", "value": 100.3 }, "CBDdist_km_coeff": { "type": "number", "value": -40.3 }, "Collector_coeff": { "type": "number", "value": 611.1 }, "Crime_coeff": { "type": "number", "value": 2.9 }, "EmployAccess_coeff": { "type": "number", "value": 0 }, "LUMix_coeff": { "type": "number", "value": -919.9 }, "MedHHInc_coeff": { "type": "number", "value": 2.1 }, "OffstreetTrail_coeff": { "type": "number", "value": 253.8 }, "PDperkm2_coeff": { "type": "number", "value": -0.035 }, "PctU5_O65_coeff": { "type": "number", "value": 32.5 }, "Pctnonwhite_coeff": { "type": "number", "value": -29.8 }, "Pctw4ormore_coeff": { "type": "number", "value": 371.4 }, "Precip_coeff": { "type": "number", "value": -127.8 }, "Principal_coeff": { "type": "number", "value": 66.4 }, "Tmax_coeff": { "type": "number", "value": -26 }, "WatDist_km_coeff": { "type": "number", "value": -21.6 }, "Year_coeff": { "type": "number", "value": -5.9 }, "constant": { "type": "number", "value": 788.6 } }, "data": { "Arterial": { "type": "property", "value": "Arterial" }, "BusRoute": { "type": "property", "value": "BusRoute" }, "CBDdist_km": { "type": "property", "value": "CBDdist_km" }, "Collector": { "type": "property", "value": "Collector" }, "Crime": { "type": "property", "value": "Crime" }, "EmployAccess": { "type": "property", "value": "EmployAccess" }, "LUMix": { "type": "property", "value": "LUMix" }, "MedHHInc": { "type": "property", "value": "MedHHInc" }, "OffstreetTrail": { "type": "property", "value": "OffstreetTrail" }, "PDperkm2": { "type": "property", "value": "PDperkm2" }, "PctU5_O65": { "type": "property", "value": "PctU5_O65" }, "Pctnonwhite": { "type": "property", "value": "Pctnonwhite" }, "Pctw4ormore": { "type": "property", "value": "Pctw4ormore" }, "Principal": { "type": "property", "value": "Principal" }, "WatDist_km": { "type": "property", "value": "WatDist_km" } }, "results": { "result": { "type": "string", "value": "ped12ols" } } }, "file_config": { "data": test_file } } data = client.get(job_uri, params={'format': 'json'}).json() data.update(payload) job_id = data['id'] response = client.put(job_uri, headers={ 'Content-Type': 'application/json', }, data=json.dumps(data)) logger.debug('Response from job update was %s', response.text) self.assertTrue( response.status_code in (204, 202), 'Expected a return code of 204/202 with valid ' + 'data provided got (%s)' % (response.status_code)) # Now check the status to wait for completion timeout = time.time() + 120 status_url = client.getURL('api', 'job_status/') params = {'job': job_id, 'format': 'json', 'limit': 1} steps = ['Parameter & data file validation complete.', 'COMPLETE'] prev_response = '' while time.time() < timeout: response = client.get(status_url, params=params) self.assertEqual(response.status_code, 200, 'Expected to get valid response back') if len(response.text): json_data = response.json() if prev_response <> response.text: logger.debug('Reponse changed to %s', response.text) prev_response = response.text if json_data['meta']['total_count']: if json_data['objects'][0]['message'] in steps: steps.remove(json_data['objects'][0]['message']) if json_data['objects'][0]['message'] == 'COMPLETE': break time.sleep(.1) self.assertEqual(len(steps), 0, 'Did not get expected message(s) %s' % (steps, )) response = client.get(job_uri, params={'format': 'json'}) json_response = response.json() self.assertTrue( json_response['status'] in ('Post-processing results', 'Complete'), 'Expected a status of Complete, not %s' % (json_response['status'])) timeout = time.time() + 120 while time.time() < timeout: if json_response['status'] == 'Complete': break response = client.get(job_uri, params={'format': 'json'}) json_response = response.json() time.sleep(.1) else: self.fail( 'Expected status to be complete after 120s timeout, not %s' % (json_response['status'])) results_uri = None for row in json_response['results_files']: if row['primary']: logger.debug("Primary results were %s", row) results_uri = client.getURL(path=row['datafile']) if not results_uri: self.fail( 'Expected to get back a primary result, none found in %s' % (json_response, )) # Try to see if another user can download this job or results.. username2, password2 = self.getUsernamePassword() user_uri = self._create_user(username2, password2) client2 = NMTKClient(self.site_url) client2.login(username=username2, password=password2) response = client2.get(job_uri, params={'format': 'json'}) self.assertEqual(response.status_code, 401, ('Expected 401 forbidden when ' + 'another user tried to get job info (not %s)') % (response.status_code, )) response = client2.get(results_uri, params={'format': 'json'}) self.assertEqual(response.status_code, 401, ('Expected 401 forbidden when ' + 'another user tried to get result (not %s)') % (response.status_code, )) response = client.get(results_uri, params={'format': 'json'}) self.assertEqual( response.status_code, 200, 'Status code expected was 200, not %s' % (response.status_code, )) logger.debug('Header is %s', response.headers) data = json.loads(response.content)
def test_user_change_password(self): ''' Verify that password change functionality functions as designed. ''' payload = {'format': 'json'} response = self.client.get(self.api_user_url, params=payload) # Create the user username, password = self.getUsernamePassword() response = self._create_user(username, password) user_url = response.headers['location'] # Create the user username2, password2 = self.getUsernamePassword() response = self._create_user(username2, password2) user2_url = response.headers['location'] client = NMTKClient(self.site_url) response = client.login(username, password) client2 = NMTKClient(self.site_url) response = client2.login(username2, password2) client_data = client.get(user_url).json() client2_data = client2.get(user2_url).json() # user changes his own password, but fails to supply old password client_data['password'] = '******' % (password, ) response = client.put(user_url, data=json.dumps(client_data)) self.assertEqual(response.status_code, 400, 'Without old password password change should fail') # login with new password client_a = NMTKClient(self.site_url) response = client_a.login(username, client_data['password']) self.assertEqual( response.status_code, 200, 'Redirect not expected after unsuccessful login (pw not changed)') # user changes his own password, but supplys bad old password client_data['current_password'] = '******' % (password, ) response = client.put(user_url, data=json.dumps(client_data)) self.assertEqual(response.status_code, 400, 'Without old password password change should fail') # login with new password client_a = NMTKClient(self.site_url) response = client_a.login(username, client_data['password']) self.assertEqual( response.status_code, 200, 'Redirect not expected after unsuccessful login (pw not changed)') # user changes his own password, but fails to supply old password client_data['current_password'] = password client.put(user_url, data=json.dumps(client_data)) # login with new password client_a = NMTKClient(self.site_url) response = client_a.login(username, client_data['password']) self.assertEqual(response.status_code, 302, 'Redirect expected after successful login') # Verify old password no longer works response = client_a.login(username, password) self.assertEqual( response.status_code, 200, 'Redirect not expected after login ' + 'attempt with old password') # User tries to change another users password client2_data['password'] = password response = client.put(user2_url, data=json.dumps(client2_data), headers={ 'Content-Type': 'application/json', }) self.assertEqual( 401, response.status_code, 'Expected to get a 401 (Unauthorized) when a ' + 'non-superuser tries to change another users password') # Verify old password still works response = client_a.login(username2, password2) self.assertEqual( response.status_code, 302, 'Redirect expected after login ' + 'attempt with original password') # Superuser tries to change user password. logger.debug( self.client.get(self.api_user_url, params={ 'format': 'json' }).json()) logger.debug('Client data is %s', client2_data) response = self.client.put(user2_url, data=json.dumps(client2_data), headers={ 'Content-Type': 'application/json', }) logger.debug('Response from put was %s: %s', response.status_code, response.text) self.assertTrue( response.status_code in (202, 204), 'Expected to get a 204 when a ' + 'superuser tries to change another users password') # Verify password change worked client2_a = NMTKClient(self.site_url) response = client2_a.login(username2, password) self.assertEqual(response.status_code, 302, 'Redirect expected after successful login') # Verify old password no longer works response = client2_a.login(username2, password2) self.assertEqual( response.status_code, 200, 'Redirect not expected after login ' + 'attempt with old password')
def test_user_change_password(self): ''' Verify that password change functionality functions as designed. ''' payload={'format': 'json' } response=self.client.get(self.api_user_url, params=payload) # Create the user username, password=self.getUsernamePassword() response=self._create_user(username, password) user_url=response.headers['location'] # Create the user username2, password2=self.getUsernamePassword() response=self._create_user(username2, password2) user2_url=response.headers['location'] client=NMTKClient(self.site_url) response=client.login(username, password) client2=NMTKClient(self.site_url) response=client2.login(username2, password2) client_data=client.get(user_url).json() client2_data=client2.get(user2_url).json() # user changes his own password, but fails to supply old password client_data['password']='******' % (password,) response=client.put(user_url, data=json.dumps(client_data)) self.assertEqual(response.status_code, 400, 'Without old password password change should fail') # login with new password client_a=NMTKClient(self.site_url) response=client_a.login(username, client_data['password']) self.assertEqual(response.status_code, 200, 'Redirect not expected after unsuccessful login (pw not changed)') # user changes his own password, but supplys bad old password client_data['current_password']='******' % (password,) response=client.put(user_url, data=json.dumps(client_data)) self.assertEqual(response.status_code, 400, 'Without old password password change should fail') # login with new password client_a=NMTKClient(self.site_url) response=client_a.login(username, client_data['password']) self.assertEqual(response.status_code, 200, 'Redirect not expected after unsuccessful login (pw not changed)') # user changes his own password, but fails to supply old password client_data['current_password']=password client.put(user_url, data=json.dumps(client_data)) # login with new password client_a=NMTKClient(self.site_url) response=client_a.login(username, client_data['password']) self.assertEqual(response.status_code, 302, 'Redirect expected after successful login') # Verify old password no longer works response=client_a.login(username, password) self.assertEqual(response.status_code, 200, 'Redirect not expected after login ' + 'attempt with old password') # User tries to change another users password client2_data['password']=password response=client.put(user2_url, data=json.dumps(client2_data), headers={'Content-Type': 'application/json',}) self.assertEqual(401, response.status_code, 'Expected to get a 401 (Unauthorized) when a ' + 'non-superuser tries to change another users password') # Verify old password still works response=client_a.login(username2, password2) self.assertEqual(response.status_code, 302, 'Redirect expected after login ' + 'attempt with original password') # Superuser tries to change user password. logger.debug(self.client.get(self.api_user_url, params={'format': 'json'}).json()) logger.debug('Client data is %s', client2_data) response=self.client.put(user2_url, data=json.dumps(client2_data), headers={'Content-Type': 'application/json',}) logger.debug('Response from put was %s: %s', response.status_code, response.text) self.assertTrue(response.status_code in (202,204), 'Expected to get a 204 when a ' + 'superuser tries to change another users password') # Verify password change worked client2_a=NMTKClient(self.site_url) response=client2_a.login(username2, password) self.assertEqual(response.status_code, 302, 'Redirect expected after successful login') # Verify old password no longer works response=client2_a.login(username2, password2) self.assertEqual(response.status_code, 200, 'Redirect not expected after login ' + 'attempt with old password')
def test_submit_job(self): ''' Verify that we can properly submit a job (form) via the API and \ get back the (eventual) results and status of the running job. Also ensure other \ users cannot download results. ''' username, password=self.getUsernamePassword() user_uri=self._create_user(username,password) client=NMTKClient(self.site_url) response=client.login(username=username, password=password) filename=self.get_support_file('test1.geojson') test_file=client.uploadData(filename, description='Test data file (MSP)') logger.debug('URI of test file is %s', test_file) tool_url=client.getURL('api','tool/') job_url=client.getURL('api','job/') response=client.get(tool_url, params={'format': 'json'}) tools=response.json()['objects'] # Get a list of all the Tool Resource URIs for Minnesota models, # since the test1.geojson file is a MN model-specific data file. for tool in tools: if 'umn' in tool['name'].lower(): tool_uri=tool['resource_uri'] break data={'tool': client.neuter_url(tool_uri), 'description': 'Test job for testing by the automated test!'} response=client.post(job_url, data=json.dumps(data), headers={'Content-Type': 'application/json',}) #logger.debug('Result from post was %s', response.text) self.assertEqual(response.status_code, 201, ('Expected job to be created - ' + 'got back %s instead') % (response.status_code,)) job_uri=response.headers['location'] # Now we have a job, let's get the form, generate the response, and # submit it back to the user. payload={ "config": { "coefficients": {"Arterial_coeff": { "type": "number", "value": 391.8 }, "BusRoute_coeff": { "type": "number", "value": 100.3 }, "CBDdist_km_coeff": { "type": "number", "value": -40.3 }, "Collector_coeff": { "type": "number", "value": 611.1 }, "Crime_coeff": { "type": "number", "value": 2.9 }, "EmployAccess_coeff": { "type": "number", "value": 0 }, "LUMix_coeff": { "type": "number", "value": -919.9 }, "MedHHInc_coeff": { "type": "number", "value": 2.1 }, "OffstreetTrail_coeff": { "type": "number", "value": 253.8 }, "PDperkm2_coeff": { "type": "number", "value": -0.035 }, "PctU5_O65_coeff": { "type": "number", "value": 32.5 }, "Pctnonwhite_coeff": { "type": "number", "value": -29.8 }, "Pctw4ormore_coeff": { "type": "number", "value": 371.4 }, "Precip_coeff": { "type": "number", "value": -127.8 }, "Principal_coeff": { "type": "number", "value": 66.4 }, "Tmax_coeff": { "type": "number", "value": -26 }, "WatDist_km_coeff": { "type": "number", "value": -21.6 }, "Year_coeff": { "type": "number", "value": -5.9 }, "constant": { "type": "number", "value": 788.6 } }, "data": { "Arterial": { "type": "property", "value": "Arterial" }, "BusRoute": { "type": "property", "value": "BusRoute" }, "CBDdist_km": { "type": "property", "value": "CBDdist_km" }, "Collector": { "type": "property", "value": "Collector" }, "Crime": { "type": "property", "value": "Crime" }, "EmployAccess": { "type": "property", "value": "EmployAccess" }, "LUMix": { "type": "property", "value": "LUMix" }, "MedHHInc": { "type": "property", "value": "MedHHInc" }, "OffstreetTrail": { "type": "property", "value": "OffstreetTrail" }, "PDperkm2": { "type": "property", "value": "PDperkm2" }, "PctU5_O65": { "type": "property", "value": "PctU5_O65" }, "Pctnonwhite": { "type": "property", "value": "Pctnonwhite" }, "Pctw4ormore": { "type": "property", "value": "Pctw4ormore" }, "Principal": { "type": "property", "value": "Principal" }, "WatDist_km": { "type": "property", "value": "WatDist_km" } }, "results": { "result": { "type": "string", "value": "ped12ols" } } }, "file_config": { "data": test_file } } data=client.get(job_uri, params={'format': 'json'}).json() data.update(payload) job_id=data['id'] response=client.put(job_uri, headers={'Content-Type': 'application/json',}, data=json.dumps(data)) logger.debug('Response from job update was %s', response.text) self.assertTrue(response.status_code in (204,202), 'Expected a return code of 204/202 with valid ' + 'data provided got (%s)' % (response.status_code)) # Now check the status to wait for completion timeout=time.time() + 120 status_url=client.getURL('api','job_status/') params={'job': job_id, 'format': 'json', 'limit': 1 } steps=['Parameter & data file validation complete.','COMPLETE'] prev_response='' while time.time() < timeout: response=client.get(status_url, params=params) self.assertEqual(response.status_code, 200, 'Expected to get valid response back') if len(response.text): json_data=response.json() if prev_response <> response.text: logger.debug('Reponse changed to %s', response.text) prev_response=response.text if json_data['meta']['total_count']: if json_data['objects'][0]['message'] in steps: steps.remove(json_data['objects'][0]['message']) if json_data['objects'][0]['message']=='COMPLETE': break time.sleep(.1) self.assertEqual(len(steps),0, 'Did not get expected message(s) %s' % (steps,)) response=client.get(job_uri, params={'format': 'json'}) json_response=response.json() self.assertTrue(json_response['status'] in ('Post-processing results', 'Complete'), 'Expected a status of Complete, not %s' % (json_response['status'])) timeout=time.time() + 120 while time.time() < timeout: if json_response['status'] == 'Complete': break response=client.get(job_uri, params={'format': 'json'}) json_response=response.json() time.sleep(.1) else: self.fail('Expected status to be complete after 120s timeout, not %s' % (json_response['status'])) results_uri=None for row in json_response['results_files']: if row['primary']: logger.debug("Primary results were %s", row) results_uri=client.getURL(path=row['datafile']) if not results_uri: self.fail('Expected to get back a primary result, none found in %s' % (json_response,)) # Try to see if another user can download this job or results.. username2, password2=self.getUsernamePassword() user_uri=self._create_user(username2,password2) client2=NMTKClient(self.site_url) client2.login(username=username2, password=password2) response=client2.get(job_uri, params={'format': 'json'}) self.assertEqual(response.status_code, 401, ('Expected 401 forbidden when ' + 'another user tried to get job info (not %s)') % (response.status_code,)) response=client2.get(results_uri, params={'format': 'json'}) self.assertEqual(response.status_code, 401, ('Expected 401 forbidden when ' + 'another user tried to get result (not %s)') % (response.status_code,)) response=client.get(results_uri, params={'format': 'json'}) self.assertEqual(response.status_code, 200, 'Status code expected was 200, not %s' % (response.status_code,)) logger.debug('Header is %s', response.headers) data=json.loads(response.content)