205 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
		
		
			
		
	
	
			205 lines
		
	
	
		
			6.6 KiB
		
	
	
	
		
			Bash
		
	
	
	
	
	
|  | #!/usr/bin/env bash
 | ||
|  | 
 | ||
|  | set -u -e -o pipefail | ||
|  | 
 | ||
|  | # Prints out usage information for the script. | ||
|  | function printUsage { | ||
|  |   echo -e "\e[1mrun-bazel-via-tunnel.sh\e[0m - Runs a bazel command using a saucelabs tunnel
 | ||
|  | 
 | ||
|  |   \e[1mUsage:\e[0m $0 --tunnel-id=<tunnel_id> \\ | ||
|  |               --username=<saucelabs_username> --key=<saucelabs_key> <bazel command> | ||
|  | 
 | ||
|  |   \e[1mExample:\e[0m ./run-bazel-via-tunnel.sh --tunnel-id=<tunnel_id> \\ | ||
|  |               --username=<saucelabs_username> --key=<saucelabs_key> \\ | ||
|  |               yarn bazel test //src:everything | ||
|  | 
 | ||
|  |   Flags: | ||
|  |     --username: The saucelabs username | ||
|  |     --key: The saucelabs access key | ||
|  |     --tunnel-id: An identifier for the saucelabs tunnel";
 | ||
|  | } | ||
|  | 
 | ||
|  | # Ensures a file is created, creating directories for the full path as needed. | ||
|  | function touch-safe { | ||
|  |   for f in "$@"; do | ||
|  |     [ -d $f:h ] || mkdir -p $f:h && command touch $f | ||
|  |   done | ||
|  | } | ||
|  | 
 | ||
|  | # The root directory of the git project the script is running in. | ||
|  | readonly GIT_ROOT_DIR=$(git rev-parse --show-toplevel 2> /dev/null) | ||
|  | # Location for the saucelabs log file. | ||
|  | readonly SAUCE_LOG_FILE=/tmp/angular/sauce-connect.log | ||
|  | # Location for the saucelabs ready to connect lock file. | ||
|  | readonly SAUCE_READY_FILE=/tmp/angular/sauce-connect-ready-file.lock | ||
|  | # Location for the saucelabs ready to connection process id lock file. | ||
|  | readonly SAUCE_PID_FILE=/tmp/angular/sauce-connect-pid-file.lock | ||
|  | # Amount of seconds we wait for sauceconnect to establish a tunnel instance. In order to not | ||
|  | # acquire CircleCI instances for too long if sauceconnect failed, we need a connect timeout. | ||
|  | readonly SAUCE_READY_FILE_TIMEOUT=120 | ||
|  | 
 | ||
|  | # Create saucelabs log file if it doesn't already exist. | ||
|  | touch-safe $SAUCE_LOG_FILE; | ||
|  | 
 | ||
|  | # Handle configuration of script from command line flags and arguments | ||
|  | OPTIONS=$(getopt -u -l tunnel-id:,username:,key:,help --options "" -- "$@") | ||
|  | # Exit if flag parsing fails. | ||
|  | if [ $? != 0 ] ; then echo "Failed to parse flags, exiting" && printUsage >&2 ; exit 1 ; fi | ||
|  | set -- $OPTIONS | ||
|  | while true; do | ||
|  |   case "$1" in | ||
|  |     --tunnel-id) | ||
|  |         shift | ||
|  |         SAUCE_TUNNEL_IDENTIFIER=$1 | ||
|  |         ;; | ||
|  |     --username) | ||
|  |         shift | ||
|  |         SAUCE_USERNAME=$1 | ||
|  |         ;; | ||
|  |     --key) | ||
|  |         shift | ||
|  |         SAUCE_ACCESS_KEY=$1 | ||
|  |         ;; | ||
|  |     --help) | ||
|  |         printUsage | ||
|  |         exit 2 | ||
|  |         ;; | ||
|  |     --) | ||
|  |         shift | ||
|  |         USER_COMMAND=$@ | ||
|  |         break | ||
|  |         ;; | ||
|  |     *) | ||
|  |         shift | ||
|  |         ;; | ||
|  |   esac | ||
|  | done | ||
|  | 
 | ||
|  | # Check each required flag and parameter | ||
|  | if [[ -z ${SAUCE_TUNNEL_IDENTIFIER+x} ]]; then | ||
|  |   echo "Missing required flag: --tunnel-id" | ||
|  |   badCommandSyntax=1 | ||
|  | fi | ||
|  | if [[ -z ${SAUCE_USERNAME+x} ]]; then | ||
|  |   echo "Missing required flag: --username" | ||
|  |   badCommandSyntax=1 | ||
|  | fi | ||
|  | if [[ -z ${SAUCE_ACCESS_KEY+x} ]]; then | ||
|  |   echo "Missing required flag: --key" | ||
|  |   badCommandSyntax=1 | ||
|  | fi | ||
|  | if [[ "${USER_COMMAND}" == "" ]]; then | ||
|  |   echo "Missing required bazel command: Bazel command for running in saucelabs tunnel" | ||
|  |   badCommandSyntax=1 | ||
|  | elif [[ ! $USER_COMMAND =~ ^(yarn bazel) ]]; then | ||
|  |   echo "The command provided must be a bazel command run via yarn, beginning with \"yarn bazel\"" | ||
|  |   badCommandSyntax=1 | ||
|  | fi | ||
|  | 
 | ||
|  | # If any required flag or parameter were found to be missing or incorrect, exit the script. | ||
|  | if [[ ${badCommandSyntax+x} ]]; then | ||
|  |   echo | ||
|  |   printUsage | ||
|  |   exit 1 | ||
|  | fi | ||
|  | 
 | ||
|  | 
 | ||
|  | # Command arguments that will be passed to sauce-connect. | ||
|  | # By default we disable SSL bumping for all requests. This is because SSL bumping is | ||
|  | # not needed for our test setup and in order to perform the SSL bumping, Saucelabs | ||
|  | # intercepts all HTTP requests in the tunnel VM and modifies them. This can cause | ||
|  | # flakiness as it makes all requests dependent on the SSL bumping middleware. | ||
|  | # See: https://wiki.saucelabs.com/display/DOCS/Troubleshooting+Sauce+Connect#TroubleshootingSauceConnect-DisablingSSLBumping | ||
|  | sauceArgs="--no-ssl-bump-domains all" | ||
|  | sauceArgs="${sauceArgs} --logfile ${SAUCE_LOG_FILE}" | ||
|  | sauceArgs="${sauceArgs} --readyfile ${SAUCE_READY_FILE}" | ||
|  | sauceArgs="${sauceArgs} --pidfile ${SAUCE_PID_FILE}" | ||
|  | sauceArgs="${sauceArgs} --tunnel-identifier ${SAUCE_TUNNEL_IDENTIFIER}" | ||
|  | sauceArgs="${sauceArgs} -u ${SAUCE_USERNAME}" | ||
|  | 
 | ||
|  | ######################### | ||
|  | # Open saucelabs tunnel # | ||
|  | ######################### | ||
|  | 
 | ||
|  | 
 | ||
|  | ${GIT_ROOT_DIR}/node_modules/sauce-connect/bin/sc -k $SAUCE_ACCESS_KEY ${sauceArgs} & | ||
|  | 
 | ||
|  | 
 | ||
|  | ######################################## | ||
|  | # Wait for saucelabs tunnel to connect # | ||
|  | ######################################## | ||
|  | counter=0 | ||
|  | 
 | ||
|  | while [[ ! -f ${SAUCE_READY_FILE} ]]; do | ||
|  |   counter=$((counter + 1)) | ||
|  | 
 | ||
|  |   # Counter needs to be multiplied by two because the while loop only sleeps a half second. | ||
|  |   # This has been made in favor of better progress logging (printing dots every half second) | ||
|  |   if [ $counter -gt $[${SAUCE_READY_FILE_TIMEOUT} * 2] ]; then | ||
|  |     echo "Timed out after ${SAUCE_READY_FILE_TIMEOUT} seconds waiting for tunnel ready file." | ||
|  |     echo "Printing logfile output:" | ||
|  |     echo "" | ||
|  |     cat ${SAUCE_LOG_FILE} | ||
|  |     exit 5 | ||
|  |   fi | ||
|  | 
 | ||
|  |   printf "." | ||
|  |   sleep 0.5 | ||
|  | done | ||
|  | 
 | ||
|  | ######################### | ||
|  | # Execute Bazel command # | ||
|  | ######################### | ||
|  | 
 | ||
|  | # Prevent immediate exit for Bazel test failures | ||
|  | set +e | ||
|  | 
 | ||
|  | ( | ||
|  |   cd $GIT_ROOT_DIR && \
 | ||
|  |   # Run bazel command with saucelabs specific environment variables passed to the action | ||
|  |   # The KARMA_WEB_TEST_MODE and SAUCE_TUNNEL_IDENTIFIER environment variables provide | ||
|  |   # envirnment variables to be read in the karma configuration file to set correct | ||
|  |   # configurations for karma saucelabs and browser configs. | ||
|  |   # Usage of these envirnment variables can be seen in this repo in | ||
|  |   # /karma-js.conf.js and /browser-providers.conf.js | ||
|  |   eval "$USER_COMMAND --define=KARMA_WEB_TEST_MODE=SL_REQUIRED \
 | ||
|  |                       --action_env=SAUCE_USERNAME=$SAUCE_USERNAME \
 | ||
|  |                       --action_env=SAUCE_ACCESS_KEY=$SAUCE_ACCESS_KEY \
 | ||
|  |                       --action_env=SAUCE_READY_FILE=$SAUCE_READY_FILE \
 | ||
|  |                       --action_env=SAUCE_PID_FILE=$SAUCE_PID_FILE \
 | ||
|  |                       --action_env=SAUCE_TUNNEL_IDENTIFIER=$SAUCE_TUNNEL_IDENTIFIER"
 | ||
|  | ) | ||
|  | BAZEL_EXIT_CODE=$? | ||
|  | echo "Exit code for bazel command was: $BAZEL_EXIT_CODE" | ||
|  | 
 | ||
|  | # Reenable immediate exit for failure exit code | ||
|  | set -e | ||
|  | 
 | ||
|  | ############################## | ||
|  | # Close the saucelabs tunnel # | ||
|  | ############################## | ||
|  | 
 | ||
|  | if [[ ! -f ${SAUCE_PID_FILE} ]]; then | ||
|  |   echo "Could not find Saucelabs tunnel PID file. Cannot stop tunnel.." | ||
|  |   exit 1 | ||
|  | fi | ||
|  | 
 | ||
|  | echo "Shutting down Sauce Connect tunnel" | ||
|  | 
 | ||
|  | # The process id for the sauce-connect instance is stored inside of the pidfile. | ||
|  | tunnelProcessId=$(cat ${SAUCE_PID_FILE}) | ||
|  | 
 | ||
|  | # Kill the process by using the PID that has been read from the pidfile. Note that | ||
|  | # we cannot use killall because CircleCI base container images don't have it installed. | ||
|  | kill ${tunnelProcessId} | ||
|  | 
 | ||
|  | while (ps -p ${tunnelProcessId} &> /dev/null); do | ||
|  |   printf "." | ||
|  |   sleep .5 | ||
|  | done | ||
|  | 
 | ||
|  | echo "" | ||
|  | echo "Sauce Connect tunnel has been shut down" | ||
|  | 
 | ||
|  | exit $BAZEL_EXIT_CODE |