def setup(): '''interactively edit the setup file. filepath must first be set''' checkForSetupFile() location = getLocation() if location: if prompt_bool('\nlocation has been configured as "%s", would you like to change this' % location): configLocation() else: configLocation() while True: if getAppliances() and not prompt_bool('\nDo you want to add/change/remove/view/check ' + \ 'an appliance that is to be used when running local tests?'): break configAppliance() while True: if not prompt_bool('\nDo you want to add/change/remove/view/check another appliance?'): break configAppliance() break currentArgs = getArgs() if currentArgs: ansi.printc('\ncurrently sb test is adding the following args') ansi.writec(currentArgs, colors.PARAM_COLOR) if prompt_bool('\nsb test can be configured to always add arguments like -s ' '\n' \ 'I have this configured to add' '\n' \ '-s --no-build-first --skip-compiled --nologcapture' '\n' \ 'to sb test' '\n' \ 'for most people this is an unneccessary configuration' '\n' 'would you like to configure this'): configArgs()
def _snapshot(self, cmd): try: runCmd(cmd, printout=True) except VBoxManageError as err: if err.msg.startswith('\n0%...'): #ignoring VBoxManage bug pass else: ansi.printc(err.msg, colors.ERROR_COLOR) raise Exception('Reverting to the snapshot "%s" failed. Make sure you are using a VM that was auto created with this script' % snapshot)
def sbSetup(): '''call this to interactively edit the setup file for the current sandbox''' global filepath if not os.path.exists( os.path.expanduser(os.path.join('~', 'test_setup.xml')) ): ansi.printc('Default setup file must be set up before a sandbox level setup file can be set up', colors.ERROR_COLOR) ansi.printc('Entering setup for default setup file', colors.WARNING_COLOR) filepath = os.path.expanduser(os.path.join('~', 'test_setup.xml')) setup() return filepath = os.path.join(testsupport.TESTROOT, 'test_setup.xml') setup()
def _filterLog(path, listener=None): with open(path, 'rt') as f: lines = f.readlines() for i in range(len(lines)): lines[i] = str(i + 1).rjust(_LINENUM_WIDTH) + ' ' + lines[i].strip() itemNum = 1 fname = os.path.basename(path) item = '%s (%d lines)' % (fname, len(lines)) rest = DELIM_COLOR + '.' * (76 - len(item)) + NORMTXT item = CMD_COLOR + str(itemNum) + ' ' + NORMTXT + item m = LASTLOG_PAT.match(fname) if m: item = item.replace(m.group(1), CMD_COLOR + m.group(1) + NORMTXT) printc(item + rest) # Cut empty lines lines = [l for l in lines if l[_REST_OFFSET:]] # Cut lines that just have delimiters lines = [l for l in lines if _NONDELIM_LINES_PAT.search(l[_REST_OFFSET:])] # Cut lines that are known to be noise at particular phases. lines = [ l for l in lines if not _GENERIC_ANT_LABEL_PAT.match(l[_REST_OFFSET:]) ] tail = path.endswith('.tmp') # Now take the final 5 lines plus any lines with errors or warnings printCount = 0 failed = False showNextLine = False lineCount = len(lines) i = 0 for line in lines: if (showNextLine or (tail and i >= lineCount - 5)): interesting = line else: interesting = _getInteresting(line) if interesting: num = LINENUM_COLOR + line[0:_LINENUM_WIDTH] rest = line[_LINENUM_WIDTH:] if _isFailure(interesting): failed = True num += ERROR_COLOR rest += NORMTXT else: num += NORMTXT printc(num + rest) printCount += 1 showNextLine = bool(_NEXT_LINE_PAT.search(line)) i += 1 if not printCount: print INDENT + '(nothing interesting)' return failed
def _filterLog(path, listener = None): with open(path, 'rt') as f: lines = f.readlines() for i in range(len(lines)): lines[i] = str(i + 1).rjust(_LINENUM_WIDTH) + ' ' + lines[i].strip() itemNum = 1 fname = os.path.basename(path) item = '%s (%d lines)' % (fname, len(lines)) rest = DELIM_COLOR + '.'*(76-len(item)) + NORMTXT item = CMD_COLOR + str(itemNum) + ' ' + NORMTXT + item m = LASTLOG_PAT.match(fname) if m: item = item.replace(m.group(1), CMD_COLOR + m.group(1) + NORMTXT) printc(item + rest) # Cut empty lines lines = [l for l in lines if l[_REST_OFFSET:]] # Cut lines that just have delimiters lines = [l for l in lines if _NONDELIM_LINES_PAT.search(l[_REST_OFFSET:])] # Cut lines that are known to be noise at particular phases. lines = [l for l in lines if not _GENERIC_ANT_LABEL_PAT.match(l[_REST_OFFSET:])] tail = path.endswith('.tmp') # Now take the final 5 lines plus any lines with errors or warnings printCount = 0 failed = False showNextLine = False lineCount = len(lines) i = 0 for line in lines: if (showNextLine or (tail and i >= lineCount - 5)): interesting = line else: interesting = _getInteresting(line) if interesting: num = LINENUM_COLOR + line[0:_LINENUM_WIDTH] rest = line[_LINENUM_WIDTH:] if _isFailure(interesting): failed = True num += ERROR_COLOR rest += NORMTXT else: num += NORMTXT printc(num + rest) printCount += 1 showNextLine = bool(_NEXT_LINE_PAT.search(line)) i += 1 if not printCount: print INDENT + '(nothing interesting)' return failed
def sbSetup(): '''call this to interactively edit the setup file for the current sandbox''' global filepath if not os.path.exists( os.path.expanduser(os.path.join('~', 'test_setup.xml'))): ansi.printc( 'Default setup file must be set up before a sandbox level setup file can be set up', colors.ERROR_COLOR) ansi.printc('Entering setup for default setup file', colors.WARNING_COLOR) filepath = os.path.expanduser(os.path.join('~', 'test_setup.xml')) setup() return filepath = os.path.join(testsupport.TESTROOT, 'test_setup.xml') setup()
def checkCredentials(host, user, passwd): '''checks if a login is possible with the credentials entered for an appliance''' #print not Working try: import requests, socket session = requests.session( verify=False ) #the session will store the login cookies once we're logged in #check if the PSA is up try: socket.create_connection((host, '80')).close() except: raise Exception( 'could not connect to the PSA at %s. Is the PSA is running?' % host) #logout if we are logged in try: session.get('https://%s/account/logout' % host) except: pass #try to login to the PSA loginResponse = session.get( 'https://%s/account/dologin?login=%s&password=%s' % (host, user, passwd)) whoami = session.get('https://%s/appliance/whoami' % host) assert loginResponse and whoami, 'bad or no status code(s) recieved.' if '<username>%s</username>' % user not in whoami.content: raise Exception( 'After attempting to login, the user %s was not found in the whoami response.' % user) ansi.printc('successfully logged into %s' % host, colors.CMD_COLOR) return True except Exception, exc: errorMsg = 'Error logging into Existing Appliance object with the credentials\n' \ + 'host: %s username: %s password: %s\n' % (host, user, passwd) \ + str(exc) ansi.eprintc(errorMsg, colors.ERROR_COLOR) return False
def show_logs(sb): overall_log = sb.get_log_file_path() print(overall_log) if os.path.isfile(overall_log): print('') _filterLog(overall_log) today = time.localtime(time.time()) when = time.localtime(os.stat(overall_log).st_mtime) if (when.tm_mday == today.tm_mday) and (when.tm_mon == today.tm_mon) and (when.tm_year == today.tm_year): whentxt = 'today at ' + time.strftime('%I:%M %p', when) else: whentxt = time.strftime('%a, %d %b at %I:%M %p', when) lbl = '%s log last modified %s' % (sb.get_name(), whentxt) lbl = lbl.rjust(78) lbl = lbl.replace(sb.get_name(), PARAM_COLOR + sb.get_name() + NORMTXT) print('') printc(lbl) else: print('No logs available for %s.' % sb.get_name())
def createPSA(name, branding=DEFAULT_BRANDING, release=DEFAULT_RELEASE_BRANCH, repo=None): '''creates a PSA with the specified name, branding, and release branch if repo is specified, the branding and release branch of the specified repo will be used instead''' copyVM() #create a new VM vm = VM(name, 'root', 'psa') if vm.exists(): if vm.getState() == 'running': print 'shutting down VM...' vm.forceStop() vm.revert() else: print '\nCreating new VM...' vm.importVM(LOCAL_VM_PATH) vm.modify(memory = '1024', cpus = '2', memoryBalloon = '512') vm.save() #convert newly created VM into a PSA by copying and installing RPMs vm.start() print '\nConverting VM to a PSA...' time.sleep(5) vm.copyPSAtoVM(psaBranding=branding, release=release, fullMirrorPath=repo) time.sleep(5) vm.installPSA(psaBranding=branding) vm.update() print '\n\n PSA sucessfully installed!' print 'Restarting VM after PSA install' vm.stop() vm.start() vm.save('psa-install') IPAddress = vm.getIPAddress() sys.stdout.write('\nIP Address of newly installed PSA is ') ansi.printc(str(IPAddress), colors.TITLE_COLOR) return IPAddress
def setup(): '''interactively edit the setup file. filepath must first be set''' checkForSetupFile() location = getLocation() if location: if prompt_bool( '\nlocation has been configured as "%s", would you like to change this' % location): configLocation() else: configLocation() while True: if getAppliances() and not prompt_bool('\nDo you want to add/change/remove/view/check ' + \ 'an appliance that is to be used when running local tests?'): break configAppliance() while True: if not prompt_bool( '\nDo you want to add/change/remove/view/check another appliance?' ): break configAppliance() break currentArgs = getArgs() if currentArgs: ansi.printc('\ncurrently sb test is adding the following args') ansi.writec(currentArgs, colors.PARAM_COLOR) if prompt_bool('\nsb test can be configured to always add arguments like -s ' '\n' \ 'I have this configured to add' '\n' \ '-s --no-build-first --skip-compiled --nologcapture' '\n' \ 'to sb test' '\n' \ 'for most people this is an unneccessary configuration' '\n' 'would you like to configure this'): configArgs()
def checkCredentials(host, user, passwd): '''checks if a login is possible with the credentials entered for an appliance''' #print not Working try: import requests, socket session = requests.session(verify=False) #the session will store the login cookies once we're logged in #check if the PSA is up try: socket.create_connection((host, '80')).close() except: raise Exception('could not connect to the PSA at %s. Is the PSA is running?' % host) #logout if we are logged in try: session.get('https://%s/account/logout' % host) except: pass #try to login to the PSA loginResponse = session.get('https://%s/account/dologin?login=%s&password=%s' % (host, user, passwd)) whoami = session.get('https://%s/appliance/whoami' % host) assert loginResponse and whoami, 'bad or no status code(s) recieved.' if '<username>%s</username>' % user not in whoami.content: raise Exception('After attempting to login, the user %s was not found in the whoami response.' % user) ansi.printc('successfully logged into %s'%host, colors.CMD_COLOR) return True except Exception, exc: errorMsg = 'Error logging into Existing Appliance object with the credentials\n' \ + 'host: %s username: %s password: %s\n' % (host, user, passwd) \ + str(exc) ansi.eprintc(errorMsg, colors.ERROR_COLOR) return False
def configAppliance(): '''interactively configure an appliance''' appName = prompt("\nEnter the name of an existing/new appliance: ", default=None) assert appName oldHost = oldUser = oldPasswd = None if appName in getAppliances(): oldHost, oldUser, oldPasswd = getAppInfo(appName) ansi.printc('\nwhat do you want to do with the appliance %s' % appName) ansi.writec('type ') ansi.writec('c', colors.PARAM_COLOR) ansi.printc(' to change the appliance configurations') ansi.writec('type ') ansi.writec('r', colors.PARAM_COLOR) ansi.printc(' to remove the appliance from the setup file') ansi.writec('type ') ansi.writec('v', colors.PARAM_COLOR) ansi.printc(' to view info about the appliance\'s configuration') ansi.writec('type ') ansi.writec('check', colors.PARAM_COLOR) ansi.printc(' to check the credentials of the appliance') response = prompt('\n', choices='options: c, r, v, check', default='v') if response == 'c': print 'Changing an appliance isn\'t working right now \n the setup file must be manually changed' pass elif response == 'v': displayApplianceInfo(appName) return elif response == 'r': delAppliance(appName) return elif response == 'check': checkCredentials(oldHost, oldUser, oldPasswd) return else: ansi.eprintc('not a valid option', colors.ERROR_COLOR) return host = prompt('\nwhat is the ip address for "%s"' % appName, default=oldHost) name = prompt('\nwhat is the username for the appliance "%s"' % appName, default=oldUser) passwd = prompt('\nwhat is the password for "%s"' % appName, default=oldPasswd) if prompt_bool( '\nWould you like to check the entered credentials for "%s"? (%s must be running):' % (appName, appName)): if not checkCredentials(host, name, passwd): ansi.printc('failed to set up %s' % appName, colors.WARNING_COLOR) return print '\n%s successfully configured. You can now use the appliance %s ' \ 'to run tests by using the command' % (appName, appName) ansi.printc('sb test --psa %s\n' % appName, colors.TITLE_COLOR) setAppliance(appName, host, name, passwd) return
def configAppliance(): '''interactively configure an appliance''' appName = prompt("\nEnter the name of an existing/new appliance: ", default=None) assert appName oldHost = oldUser = oldPasswd = None if appName in getAppliances(): oldHost, oldUser, oldPasswd = getAppInfo(appName) ansi.printc('\nwhat do you want to do with the appliance %s' % appName) ansi.writec('type '); ansi.writec('c', colors.PARAM_COLOR); ansi.printc(' to change the appliance configurations') ansi.writec('type '); ansi.writec('r', colors.PARAM_COLOR); ansi.printc(' to remove the appliance from the setup file') ansi.writec('type '); ansi.writec('v', colors.PARAM_COLOR); ansi.printc(' to view info about the appliance\'s configuration') ansi.writec('type '); ansi.writec('check', colors.PARAM_COLOR); ansi.printc(' to check the credentials of the appliance') response = prompt('\n', choices='options: c, r, v, check', default='v') if response == 'c': print 'Changing an appliance isn\'t working right now \n the setup file must be manually changed' pass elif response == 'v': displayApplianceInfo(appName) return elif response == 'r': delAppliance(appName) return elif response == 'check': checkCredentials(oldHost, oldUser, oldPasswd) return else: ansi.eprintc('not a valid option', colors.ERROR_COLOR) return host = prompt('\nwhat is the ip address for "%s"' % appName, default=oldHost) name = prompt('\nwhat is the username for the appliance "%s"' % appName, default=oldUser) passwd = prompt('\nwhat is the password for "%s"' % appName, default=oldPasswd) if prompt_bool('\nWould you like to check the entered credentials for "%s"? (%s must be running):' % (appName, appName)): if not checkCredentials(host, name, passwd): ansi.printc('failed to set up %s' % appName, colors.WARNING_COLOR) return print '\n%s successfully configured. You can now use the appliance %s ' \ 'to run tests by using the command' % (appName, appName) ansi.printc('sb test --psa %s\n' % appName, colors.TITLE_COLOR) setAppliance(appName, host, name, passwd) return
def main(argv): try: if '-h' in argv or '--help' in argv: return run_nose(argv) sb = Sandbox(SBROOT) #Add different options for using an appliance to run a test #more info about this can be found at #https:// ... /working-with-code/concepts/existing-appliances/run-tests-using-an-appliance # TODO refer to correct doc site #TODO move all the info below into the above website. # #This can # speed things up when creating test # Allows one to debug a test with a full appliance # can be used to run tests with an appliance setup from a variety of repos # #This does not # Replace the current system of running tests off of a sandbox as an appliance # Does not leave behind it's files in a way that is easy to inspect # Is not as reproducable of an environment # #The different options available are # --setup sets up appliances to run tests off of, as well as some # other setup options related to tests # --sb-setup same as --setup, but is specific to the current sandbox # --ip ipaddress --ea applianceName --user username --passwd password # accomplishes the same thing as --setup, but without going through the interactive prompts # --no-adding-args using --setup sb test can be set up to automatically add # arguments when you run sb test, this prevents that from happening # --app someApplianceName the setup file created with --setup or --sb-setup # maps a user defined name with the appliance credentials. You can specify the name # of one of those appliances to run test off of, or you can use a new name and # a brand new appliance will be created and used. You can then reuse that appliance as many times as desired # --recreate-psa this can only be used with an appliance that was previously created # with the above command. This restores the VM to a snapshot before any PSA RPMs were # copied over and installed, the VM then refetches all of the necessary RPMs and # installs them # --branding someBranding --release release_branch these can be used to specify the branding and release # branch when creating a PSA # --repo this can be used instead of the above command to specify a different repo to install off of # this command overrides any branding or release branches that were specified with the above command if '--setup' in argv: argv.remove('--setup') isetup.defaultSetup() print '\n' sys.exit('setup is complete') if '--sb-setup' in argv: argv.remove('--sb-setup') isetup.sbSetup() print '\n' sys.exit('setup is complete') global addingArgs if '--no-adding-args' in argv: addingArgs = False argv.remove('--no-adding-args') if addingArgs: argsToAdd = getAdditionalArgs() if argsToAdd: added = '' for arg in argsToAdd.split(): if arg not in argv: added += ' ' + arg argv.append(arg) if added: print 'added', added global_vars.ea = None ip = None user = None passwd = None def retreiveAndDelArg(arg): for i, tryArg in enumerate(argv): if tryArg == arg: ret = argv[i + 1] del argv[i] del argv[i] return ret branding = None release = None repo = None for i, arg in enumerate(argv): if arg == '--ea' or arg == '--psa': global_vars.ea = argv[i + 1] del argv[i] del argv[i] for i, arg in enumerate(argv): if arg == '--ip' or arg == '--host': ip = argv[i + 1] del argv[i] del argv[i] for i, arg in enumerate(argv): if arg == '--user': user = argv[i + 1] del argv[i] del argv[i] for i, arg in enumerate(argv): if arg == '--passwd' or arg == '--password': passwd = argv[i + 1] del argv[i] del argv[i] for i, arg in enumerate(argv): if arg == '--release': release = argv[i + 1] del argv[i] del argv[i] for i, arg in enumerate(argv): if arg == '--branding': branding = argv[i + 1] del argv[i] del argv[i] for i, arg in enumerate(argv): if arg == '--repo': repo = argv[i + 1] del argv[i] del argv[i] if global_vars.ea and ip and user and passwd: setup.setSetupFile() setup.configAppliance(global_vars.ea, ip, user, passwd) #make sure we're creating a new PSA if an appliance sandbox type is being used if 'appliance' in sb.get_sandboxtype().get_variant(): global_vars.ea = 'sb-test-appliance' if '--recreate-psa' not in argv and global_vars.ea in isetup.getAppliances(): argv.append('--recreate-psa') isetup.setSetupFile() #create the appliance if the appliance doesn't exist in the setup file if global_vars.ea and global_vars.ea not in isetup.getAppliances(): ansi.printc('Appliance %s does not exist, will attempt to create it in 5 seconds, push ctrl+c to cancel' % global_vars.ea, colors.WARNING_COLOR) time.sleep(5) ip = controlVM.createPSA(global_vars.ea, branding, release, repo) isetup.setAppliance(global_vars.ea, ip, 'root', 'psa') if '--recreate-psa' in argv: assert global_vars.ea, 'A VM must be specified with the --ea option to use the --recreate-psa option' controlVM.createPSA(global_vars.ea, branding, release, repo) argv.remove('--recreate-psa') # Support "modes" of tests. This allows us to run a set of tests in # more than one way -- for example, with valgrind enabled or disabled, # or with SearchServer using hs5 versus hs3. mode_path = os.path.join(sb.get_root(), _MODE_FILE) argv, modes = get_modes(argv) if os.path.isfile(mode_path): os.remove(mode_path) if modes: if modes[0].lower() != 'none': with open(mode_path, 'w') as f: f.write(','.join(modes)) attr_arg = find_attr_arg_index(argv) if len(modes) == 0 and attr_arg is None: modeattrs = sb.get_sandboxtype().get_test_mode_attrs_combo() result = 0 runcompiled = True runcodescan = True for modeattr in modeattrs.split(';'): runnable_assembly._modes = None if modeattr.find(':') == -1: if len(modeattr) > 3: print('Skipping mode+attr combo "%s" because no separator ":" was found' % modeattr) continue print('Running mode+attr combo: %s' % modeattr) mode, attrs = modeattr.split(':') argnew = argv[:]#copy argv into argnew so we can append things for this round of tests argnew.insert(1, '-A') argnew.insert(2, attrs.strip()) argnew.insert(3, '--mode') argnew.insert(4, mode.strip()) if not runcompiled: argnew.append('--skip-compiled') if not runcodescan: argnew.append('--skip-codescan') result = result + main(argnew); runcompiled = False runcodescan = False print("") if result == 0: print("All test combos passed.") else: print("%s test combos failed!" % result) return result elif attr_arg is None: argv.insert(1, '-A') attrs = sb.get_sandboxtype().get_test_attrs() argv.insert(2, attrs) print('Running tests that are: %s.' % attrs) else: # If we're running interactive tests, make sure we're also # running with the -s switch. print('Running tests that are: %s.' % argv[attr_arg + 1]) x = argv[attr_arg + 1].replace('not ', '!') if 'interactive' in x and '!interactive' not in x: if '-s' not in argv: argv.insert(1, '-s') if len(modes) > 0: if modes[0].lower() == 'none': modes = [] print('Running modes: %s' % ','.join(modes)) # Make sure any path args in the arg list are fully normalized so they # are not sensitive to working directory changes. normalize_path_args(argv) # If we're collecting tests, it's virtually guaranteed that we want to # display the list... if '--collect-only' in argv: if '-v' not in argv and '--verbose' not in argv: verbosity_found = False for a in argv: if a.startswith('--verbosity'): verbosity_found = True break if not verbosity_found: argv.append('--verbose') # The "full" flag tells us to test all components in the sandbox, # instead of just the ones that are present in code form. If our scope # is full, no special effort is required. However, if our scope is # normal (quick), we have to tell nose which subdirs to use during # discovery. if not SPECIFIC_TESTS_SELECTED: global quick if '--full' in argv: argv.remove('--full') quick = False if '--quick' in argv: quick = True argv.remove('--quick') if quick: subset = [] cr = sb.get_code_root() tr = sb.get_test_root() deps = [l.name for l in sb.get_cached_components()] for c in deps: if component.CODE_ASPECT_NAME in sb.get_component_aspects(c) or c == sb.get_top_component(): component_test_root = sb.get_component_path(c, component.TEST_ASPECT_NAME) if os.path.isdir(component_test_root): if could_have_tests(component_test_root): # Nose treats the first --where arg as a specifier # of the working directory, and subsequent --where # args as folders to use for discovery. So if we're # going to add --where, we have to guarantee working # dir is the first --where. if not subset: argv.append('--where') argv.append(sb.get_root()) argv.append('--where') argv.append(component_test_root) subset.append(c) if subset: print('Targeting: ' + ', '.join(subset) + ' (--full to override).') # The default behavior of the "sb test" command is supposed to be that # all tests get run, no matter what part of the sandbox you're in when # you invoke the command. This is consistent with "sb build", "sb publish", # and other sandbox-level commands. By default, nose will discover tests # beginning in the current working directory. We could override nose's # behavior by adding an extra arg that specifies that the scope for # discovery is the test root, but this would interfere with other logic # that we have, that disables the running of compiled tests when any # sort of constraining file/directory scope is given. So the simplest # way to achieve our goal is to temporarily set the current working dir # to the test root whenever no explicit scope is provided. try: restore_dir = os.getcwd() os.chdir(sb.get_test_root()) # always run tests with the current directory being the test root if '--with-id' not in argv: argv.insert(1, '--with-id') if '--auto' in argv: argv.remove('--auto') auto_test(sb, argv) else: if '--build-first' in argv: sb.set_auto_build(True) argv.remove('--build-first') err = build.main([]) if err: return err elif '--no-build-first' in argv: sb.set_auto_build(False) argv.remove('--no-build-first') # Before running tests, automatically build sandbox if it's out of date. # This allows testers to get a built sandbox and immediately run tests. It # also allows developers to repeatedly code and test without explicitly # rebuilding in between. elif sb.needs_build() and sb.get_auto_build(): print(''' Built artifacts are out of date and will be refreshed before running tests. To run tests without automatic build as needed, use "--no-build-first". ''') err = build.main([]) if err: return err return 0 if run_all(sb, argv) else 1 finally: os.chdir(restore_dir) except: print(traceback.print_exc()) return 1 # make sure bad things show up as an error