******************** Command-line scripts ******************** Launchpad includes some command-line scripts to make Launchpad integration easier for third-party libraries that aren't written in Python or that can't do token authorization by opening a user's web browser. This file tests the workflow underlying the command-line scripts as best it can. RequestTokenApp =============== This class is called by the command-line script launchpad-request-token. It creates a request token on a given Launchpad installation, and returns a JSON description of the request token and the available access levels. >>> import simplejson >>> from launchpadlib.apps import RequestTokenApp >>> web_root = "http://launchpad.dev:8085/" >>> consumer_name = "consumer" >>> token_app = RequestTokenApp(web_root, consumer_name, "context") >>> json = simplejson.loads(token_app.run()) >>> sorted(json.keys()) ['access_levels', 'lp.context', 'oauth_token', 'oauth_token_consumer', 'oauth_token_secret'] >>> print json['lp.context'] context >>> print json['oauth_token_consumer'] consumer TrustedTokenAuthorizationConsoleApp =================================== This class is called by the command-line script launchpad-credentials-console. It asks for the user's Launchpad username and password, and authorizes a request token on their behalf. >>> from launchpadlib.apps import TrustedTokenAuthorizationConsoleApp >>> from launchpadlib.testing.helpers import UserInput This class does not create the request token, or exchange it for the access token--that's the job of the program that calls launchpad-credentials-console. So we'll use the request token created earlier by RequestTokenApp. >>> request_token = json['oauth_token'] Since this is a test, we don't want the application to call sys.exit() or try to open up pages in a web browser. This subclass of TrustedTokenAuthorizationConsoleApp will print messages instead of performing such un-doctest-like actions. >>> class ConsoleApp(TrustedTokenAuthorizationConsoleApp): ... def open_page_in_user_browser(self, url): ... """Print a status message.""" ... self.output("[If this were a real application, the " ... "end-user's web browser would be opened " ... "to %s]" % url) ... ... def exit_with(self, code): ... print "Application exited with code %d" % code We'll use a UserInput object to simulate a user typing things in at the prompt and hitting enter. This UserInput runs the program correctly, entering the Launchpad username and password, choosing an access level, and hitting Enter to exit. >>> username = "salgado@ubuntu.com" >>> password = "zeca" >>> fake_input = UserInput([username, password, "1", ""]) Here's a successful run of the application. When the request token is authorized, the script's response code is 0. >>> app = ConsoleApp( ... web_root, consumer_name, request_token, ... 'READ_PRIVATE, READ_PUBLIC', input_method=fake_input) >>> app.run() Launchpad credential client (console) ------------------------------------- An application identified as "consumer" wants to access Launchpad... What email address do you use on Launchpad? (No Launchpad account? Just hit enter.) [User input: salgado@ubuntu.com] What's your Launchpad password? [User input: zeca] Now it's time for you to decide how much power to give "consumer"... 1: Read Non-Private Data 2: Read Anything What should "consumer" be allowed to do...? [1-2 or Q] [User input: 1] Okay, I'm telling Launchpad to grant "consumer" access to your account. You're all done!... Press enter to go back to "consumer". [User input: ] Application exited with code 0 Now that the request token has been authorized, we'll need to create another one to continue the test. >>> json = simplejson.loads(token_app.run()) >>> request_token = json['oauth_token'] >>> app.request_token = request_token Invalid input is ignored. The user may enter 'Q' instead of a number to refuse to authorize the request token. When the user denies access, the exit code is -2. >>> fake_input = UserInput([username, password, "A", "99", "Q", ""]) >>> app.input_method = fake_input >>> app.run() Launchpad credential client (console) ------------------------------------- An application identified as "consumer"... What should "consumer" be allowed to do...? [1-2 or Q] [User input: A] What should "consumer" be allowed to do...? [1-2 or Q] [User input: 99] What should "consumer" be allowed to do...? [1-2 or Q] [User input: Q] Okay, I'm going to cancel the request... You're all done! "consumer" still doesn't have access... Press enter to go back to "consumer". [User input: ] Application exited with code -2 When the third-party application will allow only one level of access, the end-user is presented with a yes-or-no choice instead of a list to choose from. Again, invalid input is ignored. >>> json = simplejson.loads(token_app.run()) >>> request_token = json['oauth_token'] >>> fake_input = UserInput([username, password, "1", "Q", "Y", ""]) >>> app = ConsoleApp( ... web_root, consumer_name, request_token, ... 'READ_PRIVATE', input_method=fake_input) >>> app.run() Launchpad credential client (console) ------------------------------------- An application identified as "consumer"... Do you want to give "consumer" this level of access? [YN] [User input: 1] Do you want to give "consumer" this level of access? [YN] [User input: Q] Do you want to give "consumer" this level of access? [YN] [User input: Y] ... Application exited with code 0 Error handling -------------- When the end-user refuses to authorize the request token, the app exits with a return code of -2, as seen above. When any other error gets in the way of the authorization of the request token, the app's return code is -1. If the user hits enter when asked for their email address, indicating that they don't have a Launchpad account, the app opens their browser to the Launchpad login page. >>> json = simplejson.loads(token_app.run()) >>> app.request_token = json['oauth_token'] >>> input_nothing = UserInput(["", ""]) >>> app.input_method = input_nothing >>> app.run() Launchpad credential client (console) ------------------------------------- An application identified as "consumer"... [If this were a real application, the end-user's web browser...] OK, you'll need to get yourself a Launchpad account before... I'm opening the Launchpad registration page in your web browser... Press enter to go back to "consumer". [User input: ] Application exited with code -1 If the user keeps entering bad passwords, the app eventually gives up. >>> input_bad_password = UserInput( ... [username, "badpw", "", "badpw", "", "badpw", ""]) >>> json = simplejson.loads(token_app.run()) >>> request_token = json['oauth_token'] >>> app.request_token = request_token >>> app.input_method = input_bad_password >>> app.run() Launchpad credential client (console) ------------------------------------- An application identified as "consumer"... What email address do you use on Launchpad? (No Launchpad account? Just hit enter.) [User input: salgado@ubuntu.com] What's your Launchpad password? [User input: badpw] I can't log in with the credentials you gave me. Let's try again. What email address do you use on Launchpad? [salgado@ubuntu.com] [User input: ] What's your Launchpad password? [User input: badpw] I can't log in with the credentials you gave me. Let's try again. What email address do you use on Launchpad? [salgado@ubuntu.com] [User input: ] What's your Launchpad password? [User input: badpw] You've failed the password entry too many times... Press enter to go back to "consumer". [User input: ] Application exited with code -1