def test_get_token_and_login_is_deprecated(self): # get_token_and_login() works but triggers a deprecation warning. with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("always") NoNetworkLaunchpad.get_token_and_login('consumer') self.assertEquals(len(caught), 1) self.assertEquals(caught[0].category, DeprecationWarning)
def test_login_is_deprecated(self): # login() works but triggers a deprecation warning. with warnings.catch_warnings(record=True) as caught: warnings.simplefilter("always") warnings.simplefilter("ignore", PendingDeprecationWarning) NoNetworkLaunchpad.login('consumer', 'token', 'secret') self.assertEqual(len(caught), 1) self.assertEqual(caught[0].category, DeprecationWarning)
def test_authorization_engine_is_propagated(self): # You can pass in a custom authorization engine, which will be # used to get a request token and exchange it for an access # token. engine = NoNetworkAuthorizationEngine(SERVICE_ROOT, 'application name') NoNetworkLaunchpad.login_with(authorization_engine=engine) self.assertEquals(engine.request_tokens_obtained, 1) self.assertEquals(engine.access_tokens_obtained, 1)
def test_credentials_save_fail_under_sudo_does_not_raise_exception(self): # When running under sudo, Launchpad will not attempt to use # the keyring, so credential save failure will never happen launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') service_root = "http://api.example.com/" with fake_keyring(BadSaveKeyring()): NoNetworkLaunchpad.login_with('not important', service_root=service_root, launchpadlib_dir=launchpadlib_dir)
def test_authorization_engine_is_propagated(self): # You can pass in a custom authorization engine, which will be # used to get a request token and exchange it for an access # token. engine = NoNetworkAuthorizationEngine( SERVICE_ROOT, 'application name') NoNetworkLaunchpad.login_with(authorization_engine=engine) self.assertEquals(engine.request_tokens_obtained, 1) self.assertEquals(engine.access_tokens_obtained, 1)
def test_dirs_created_are_secure(self): launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') NoNetworkLaunchpad.login_with( 'not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) self.assertTrue(os.path.isdir(launchpadlib_dir)) # Verify the mode is safe statinfo = os.stat(launchpadlib_dir) mode = stat.S_IMODE(statinfo.st_mode) self.assertEqual(mode, stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
def test_dirs_created_are_changed_to_secure(self): launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') # Verify a newly created-by-hand directory is insecure os.mkdir(launchpadlib_dir) os.chmod(launchpadlib_dir, 0755) self.assertTrue(os.path.isdir(launchpadlib_dir)) statinfo = os.stat(launchpadlib_dir) mode = stat.S_IMODE(statinfo.st_mode) self.assertNotEqual(mode, stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC) NoNetworkLaunchpad.login_with( 'not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) # Verify the mode has been changed to 0700 statinfo = os.stat(launchpadlib_dir) mode = stat.S_IMODE(statinfo.st_mode) self.assertEqual(mode, stat.S_IWRITE | stat.S_IREAD | stat.S_IEXEC)
def test_no_credentials_creates_new_credential(self): # If no credentials are found, a desktop-wide credential is created. timeout = object() proxy_info = object() launchpad = NoNetworkLaunchpad.login_with( 'app name', launchpadlib_dir=self.temp_dir, service_root=SERVICE_ROOT, timeout=timeout, proxy_info=proxy_info) # Here's the new credential. self.assertEqual(launchpad.credentials.access_token.key, NoNetworkAuthorizationEngine.ACCESS_TOKEN_KEY) self.assertEqual(launchpad.credentials.consumer.application_name, 'app name') self.assertEquals(launchpad.authorization_engine.allow_access_levels, ['DESKTOP_INTEGRATION']) # The expected arguments were passed in to the Launchpad # constructor. expected_arguments = dict(service_root=SERVICE_ROOT, cache=os.path.join(self.temp_dir, 'api.example.com', 'cache'), timeout=timeout, proxy_info=proxy_info, version=NoNetworkLaunchpad.DEFAULT_VERSION) self.assertEqual(launchpad.passed_in_args, expected_arguments)
def test_existing_credentials_arguments_passed_on(self): # When re-using existing credentials, the arguments login_with # is called with are passed on the the __init__() method. os.makedirs( os.path.join(self.temp_dir, 'api.example.com', 'credentials')) credentials_file_path = os.path.join( self.temp_dir, 'api.example.com', 'credentials', 'app name') credentials = Credentials( 'app name', consumer_secret='consumer_secret:42', access_token=AccessToken('access_key:84', 'access_secret:168')) credentials.save_to_path(credentials_file_path) timeout = object() proxy_info = object() version = "foo" launchpad = NoNetworkLaunchpad.login_with( 'app name', launchpadlib_dir=self.temp_dir, service_root=SERVICE_ROOT, timeout=timeout, proxy_info=proxy_info, version=version) expected_arguments = dict( service_root=SERVICE_ROOT, timeout=timeout, proxy_info=proxy_info, version=version, cache=os.path.join(self.temp_dir, 'api.example.com', 'cache')) for key, expected in expected_arguments.items(): actual = launchpad.passed_in_args[key] self.assertEqual(actual, expected)
def test_credentials_save_failed(self): # If saving the credentials did not succeed and a callback was # provided, it is called. callback_called = [] def callback(): # Since we can't rebind "callback_called" here, we'll have to # settle for mutating it to signal success. callback_called.append(None) launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') service_root = "http://api.example.com/" with fake_keyring(BadSaveKeyring()): NoNetworkLaunchpad.login_with( 'not important', service_root=service_root, launchpadlib_dir=launchpadlib_dir, credential_save_failed=callback) self.assertEquals(len(callback_called), 1)
def test_version_is_propagated(self): # Make sure the login_with() method conveys the 'version' # argument all the way to the Launchpad object. The # credentials will be cached to disk. launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') launchpad = NoNetworkLaunchpad.login_with( 'not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir, version="foo") self.assertEquals(launchpad.passed_in_args['version'], 'foo') # Now execute the same test a second time. This time, the # credentials are loaded from disk and a different code path # is executed. We want to make sure this code path propagates # the 'version' argument. launchpad = NoNetworkLaunchpad.login_with( 'not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir, version="bar") self.assertEquals(launchpad.passed_in_args['version'], 'bar')
def test_short_service_name(self): # A short service name is converted to the full service root URL. launchpad = NoNetworkLaunchpad.login_with('app name', 'staging') self.assertEqual(launchpad.passed_in_args['service_root'], 'https://api.staging.launchpad.net/') # A full URL as the service name is left alone. launchpad = NoNetworkLaunchpad.login_with( 'app name', uris.service_roots['staging']) self.assertEqual(launchpad.passed_in_args['service_root'], uris.service_roots['staging']) # A short service name that does not match one of the # pre-defined service root names, and is not a valid URL, # raises an exception. launchpad = ('app name', 'https://') self.assertRaises(ValueError, NoNetworkLaunchpad.login_with, 'app name', 'foo')
def test_desktop_integration_doesnt_happen_without_consumer_name(self): # The only way to do a non-desktop integration is to specify a # consumer_name. If you specify application_name instead, your # value for allow_access_levels is ignored, and a desktop # integration is performed. launchpad = NoNetworkLaunchpad.login_with( 'application name', allow_access_levels=['FOO']) self.assertEquals(launchpad.authorization_engine.allow_access_levels, ['DESKTOP_INTEGRATION'])
def test_non_desktop_integration(self): # When doing a non-desktop integration, you must specify a # consumer_name. You can pass a list of allowable access # levels into login_with(). launchpad = NoNetworkLaunchpad.login_with(consumer_name="consumer", allow_access_levels=['FOO']) self.assertEqual(launchpad.credentials.consumer.key, "consumer") self.assertEqual(launchpad.credentials.consumer.application_name, None) self.assertEqual(launchpad.authorization_engine.allow_access_levels, ['FOO'])
def test_dirs_created(self): # The path we pass into login_with() is the directory where # cache for all service roots are stored. launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') NoNetworkLaunchpad.login_with('not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) # The 'launchpadlib' dir got created. self.assertTrue(os.path.isdir(launchpadlib_dir)) # A directory for the passed in service root was created. service_path = os.path.join(launchpadlib_dir, 'api.example.com') self.assertTrue(os.path.isdir(service_path)) # Inside the service root directory, there is a 'cache' # directory. self.assertTrue(os.path.isdir(os.path.join(service_path, 'cache'))) # In older versions there was also a 'credentials' directory, # but no longer. credentials_path = os.path.join(service_path, 'credentials') self.assertFalse(os.path.isdir(credentials_path))
def test_non_desktop_integration(self): # When doing a non-desktop integration, you must specify a # consumer_name. You can pass a list of allowable access # levels into login_with(). launchpad = NoNetworkLaunchpad.login_with( consumer_name="consumer", allow_access_levels=['FOO']) self.assertEquals(launchpad.credentials.consumer.key, "consumer") self.assertEquals(launchpad.credentials.consumer.application_name, None) self.assertEquals(launchpad.authorization_engine.allow_access_levels, ['FOO'])
def test_filename(self): ignore, filename = tempfile.mkstemp() launchpad = NoNetworkLaunchpad.login_with( application_name='not important', credentials_file=filename) # The credentials are stored unencrypted in the file you # specify. credentials = Credentials.load_from_path(filename) self.assertEquals(credentials.consumer.key, launchpad.credentials.consumer.key) os.remove(filename)
def test_short_service_name(self): # A short service name is converted to the full service root URL. launchpad = NoNetworkLaunchpad.login_with('app name', 'staging') self.assertEqual( launchpad.passed_in_args['service_root'], 'https://api.staging.launchpad.net/') # A full URL as the service name is left alone. launchpad = NoNetworkLaunchpad.login_with( 'app name', uris.service_roots['staging']) self.assertEqual( launchpad.passed_in_args['service_root'], uris.service_roots['staging']) # A short service name that does not match one of the # pre-defined service root names, and is not a valid URL, # raises an exception. launchpad = ('app name', 'https://') self.assertRaises( ValueError, NoNetworkLaunchpad.login_with, 'app name', 'foo')
def test_dirs_created(self): # The path we pass into login_with() is the directory where # cache for all service roots are stored. launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') NoNetworkLaunchpad.login_with( 'not important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) # The 'launchpadlib' dir got created. self.assertTrue(os.path.isdir(launchpadlib_dir)) # A directory for the passed in service root was created. service_path = os.path.join(launchpadlib_dir, 'api.example.com') self.assertTrue(os.path.isdir(service_path)) # Inside the service root directory, there is a 'cache' # directory. self.assertTrue( os.path.isdir(os.path.join(service_path, 'cache'))) # In older versions there was also a 'credentials' directory, # but no longer. credentials_path = os.path.join(service_path, 'credentials') self.assertFalse(os.path.isdir(credentials_path))
def test_application_name_is_propagated(self): # Create a Launchpad instance for a given application name. # Credentials are stored, but they don't include the # application name, since multiple applications may share a # single system-wide credential. launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') launchpad = NoNetworkLaunchpad.login_with( 'very important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) self.assertEquals( launchpad.credentials.consumer.application_name, 'very important') # Now execute the same test a second time. This time, the # credentials are loaded from disk and a different code path # is executed. We want to make sure this code path propagates # the application name, instead of picking an empty one from # disk. launchpad = NoNetworkLaunchpad.login_with( 'very important', service_root=SERVICE_ROOT, launchpadlib_dir=launchpadlib_dir) self.assertEquals( launchpad.credentials.consumer.application_name, 'very important')
def test_anonymous_login(self): """Test the anonymous login helper function.""" launchpad = NoNetworkLaunchpad.login_anonymously( 'anonymous access', launchpadlib_dir=self.temp_dir, service_root=SERVICE_ROOT) self.assertEqual(launchpad.credentials.access_token.key, '') self.assertEqual(launchpad.credentials.access_token.secret, '') # Test that anonymous credentials are not saved. credentials_path = os.path.join( self.temp_dir, 'api.example.com', 'credentials', 'anonymous access') self.assertFalse(os.path.exists(credentials_path))
def test_same_app_different_servers(self): launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') keyring = InMemoryKeyring() # Be paranoid about the keyring starting out empty. assert not keyring.data, 'oops, a fresh keyring has data in it' with fake_keyring(keyring): # Create stored credentials for the same application but against # two different sites (service roots). NoNetworkLaunchpad.login_with( 'application name', service_root='http://alpha.example.com/', launchpadlib_dir=launchpadlib_dir) NoNetworkLaunchpad.login_with( 'application name', service_root='http://beta.example.com/', launchpadlib_dir=launchpadlib_dir) # There should only be two sets of stored credentials (this assertion # is of the test mechanism, not a test assertion). assert len(keyring.data.keys()) == 2 application_key_1 = keyring.data.keys()[0][1] application_key_2 = keyring.data.keys()[1][1] self.assertNotEqual(application_key_1, application_key_2)
def test_None_launchpadlib_dir(self): # If no launchpadlib_dir is passed in to login_with, # $HOME/.launchpadlib is used. old_home = os.environ['HOME'] os.environ['HOME'] = self.temp_dir launchpad = NoNetworkLaunchpad.login_with( 'app name', service_root=SERVICE_ROOT) # Reset the environment to the old value. os.environ['HOME'] = old_home cache_dir = launchpad.passed_in_args['cache'] launchpadlib_dir = os.path.abspath( os.path.join(cache_dir, '..', '..')) self.assertEqual( launchpadlib_dir, os.path.join(self.temp_dir, '.launchpadlib')) self.assertTrue(os.path.exists( os.path.join(launchpadlib_dir, 'api.example.com', 'cache')))
def test_components_of_application_key(self): launchpadlib_dir = os.path.join(self.temp_dir, 'launchpadlib') keyring = InMemoryKeyring() service_root = 'http://api.example.com/' application_name = 'Super App 3000' with fake_keyring(keyring): launchpad = NoNetworkLaunchpad.login_with( application_name, service_root=service_root, launchpadlib_dir=launchpadlib_dir) consumer_name = launchpad.credentials.consumer.key application_key = keyring.data.keys()[0][1] # Both the consumer name (normally the name of the application) and # the service root (the URL of the service being accessed) are # included in the key when storing credentials. self.assert_(service_root in application_key) self.assert_(consumer_name in application_key) # The key used to store the credentials is of this structure (and # shouldn't change between releases or stored credentials will be # "forgotten"). self.assertEquals(application_key, consumer_name + '@' + service_root)
def test_no_credentials_creates_new_credential(self): # If no credentials are found, a desktop-wide credential is created. timeout = object() proxy_info = object() launchpad = NoNetworkLaunchpad.login_with( 'app name', launchpadlib_dir=self.temp_dir, service_root=SERVICE_ROOT, timeout=timeout, proxy_info=proxy_info) # Here's the new credential. self.assertEqual(launchpad.credentials.access_token.key, NoNetworkAuthorizationEngine.ACCESS_TOKEN_KEY) self.assertEqual(launchpad.credentials.consumer.application_name, 'app name') self.assertEquals(launchpad.authorization_engine.allow_access_levels, ['DESKTOP_INTEGRATION']) # The expected arguments were passed in to the Launchpad # constructor. expected_arguments = dict( service_root=SERVICE_ROOT, cache=os.path.join(self.temp_dir, 'api.example.com', 'cache'), timeout=timeout, proxy_info=proxy_info, version=NoNetworkLaunchpad.DEFAULT_VERSION) self.assertEqual(launchpad.passed_in_args, expected_arguments)
def test_consumer_name_identifies_app(self): # If you pass in consumer_name, that's good enough to identify # your application. NoNetworkLaunchpad.login_with(consumer_name="name")
def test_max_failed_attempts_accepted(self): # You can pass in a value for the 'max_failed_attempts' # argument, even though that argument doesn't do anything. NoNetworkLaunchpad.login_with( 'not important', max_failed_attempts=5)