Skip to content

Commit 4b8d857

Browse files
committed
restructured logic with further logic improvements
1 parent 9aa2024 commit 4b8d857

File tree

8 files changed

+1384
-1288
lines changed

8 files changed

+1384
-1288
lines changed

mac/common-utils.sh

Lines changed: 377 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,377 @@
1+
#!/bin/bash
2+
3+
source "$(dirname "$0")/device-machine-allocation.sh"
4+
5+
# # ===== Global Variables =====
6+
WORKSPACE_DIR="$HOME/.browserstack"
7+
PROJECT_FOLDER="NOW"
8+
9+
# URL handling
10+
DEFAULT_TEST_URL="https://bstackdemo.com"
11+
12+
# ===== Log files (per-run) =====
13+
LOG_DIR="$WORKSPACE_DIR/$PROJECT_FOLDER/logs"
14+
NOW_RUN_LOG_FILE=""
15+
16+
# ===== Global Variables =====
17+
USERNAME=""
18+
ACCESS_KEY=""
19+
TEST_TYPE="" # Web / App / Both
20+
TECH_STACK="" # Java / Python / JS
21+
CX_TEST_URL="$DEFAULT_TEST_URL"
22+
23+
WEB_PLAN_FETCHED=false
24+
MOBILE_PLAN_FETCHED=false
25+
TEAM_PARALLELS_MAX_ALLOWED_WEB=0
26+
TEAM_PARALLELS_MAX_ALLOWED_MOBILE=0
27+
28+
# App specific globals
29+
APP_URL=""
30+
APP_PLATFORM="" # ios | android | all
31+
32+
33+
# ===== Logging Functions =====
34+
log_msg_to() {
35+
local message="$1"
36+
local dest_file=$NOW_RUN_LOG_FILE
37+
local ts
38+
ts="$(date +"%Y-%m-%d %H:%M:%S")"
39+
local line="[$ts] $message"
40+
41+
# print to console
42+
if [[ "$RUN_MODE" == *"--debug"* ]]; then
43+
echo "$line"
44+
fi
45+
46+
# write to dest file if provided
47+
if [ -n "$dest_file" ]; then
48+
mkdir -p "$(dirname "$dest_file")"
49+
echo "$line" >> $NOW_RUN_LOG_FILE
50+
fi
51+
}
52+
53+
# Spinner function for long-running processes
54+
show_spinner() {
55+
local pid=$1
56+
local spin='|/-\'
57+
local i=0
58+
local ts
59+
ts="$(date +"%Y-%m-%d %H:%M:%S")"
60+
while kill -0 "$pid" 2>/dev/null; do
61+
i=$(( (i+1) %4 ))
62+
printf "\r⏳ Processing... ${spin:$i:1}"
63+
sleep 0.1
64+
done
65+
echo ""
66+
log_info "Run Test command completed."
67+
sleep 5
68+
#log_msg_to "✅ Done!"
69+
}
70+
71+
# ===== Workspace Management =====
72+
setup_workspace() {
73+
log_section "⚙️ Environment & Credentials"
74+
local full_path="$WORKSPACE_DIR/$PROJECT_FOLDER"
75+
if [ ! -d "$full_path" ]; then
76+
mkdir -p "$full_path"
77+
log_info "Created onboarding workspace: $full_path"
78+
else
79+
log_success "Onboarding workspace found at: $full_path"
80+
fi
81+
}
82+
83+
84+
# ===== App Upload Management =====
85+
handle_app_upload() {
86+
local app_platform=""
87+
if [[ "$RUN_MODE" == *"--silent"* || "$RUN_MODE" == *"--debug"* ]]; then
88+
upload_sample_app
89+
app_platform="android"
90+
export APP_PLATFORM="$app_platform"
91+
log_msg_to "Exported APP_PLATFORM=$APP_PLATFORM"
92+
else
93+
local choice
94+
choice=$(osascript -e '
95+
display dialog "How would you like to select your app?" ¬
96+
with title "BrowserStack App Upload" ¬
97+
with icon note ¬
98+
buttons {"Use Sample App", "Upload my App (.apk/.ipa)", "Cancel"} ¬
99+
default button "Upload my App (.apk/.ipa)"
100+
' 2>/dev/null)
101+
102+
if [[ "$choice" == *"Use Sample App"* ]]; then
103+
upload_sample_app
104+
app_platform="android"
105+
export APP_PLATFORM="$app_platform"
106+
log_msg_to "Exported APP_PLATFORM=$APP_PLATFORM"
107+
elif [[ "$choice" == *"Upload my App"* ]]; then
108+
upload_custom_app
109+
else
110+
return 1
111+
fi
112+
fi
113+
}
114+
115+
upload_sample_app() {
116+
log_msg_to "⬆️ Uploading sample app to BrowserStack..."
117+
local upload_response
118+
upload_response=$(curl -s -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \
119+
-X POST "https://api-cloud.browserstack.com/app-automate/upload" \
120+
-F "url=https://www.browserstack.com/app-automate/sample-apps/android/WikipediaSample.apk")
121+
122+
app_url=$(echo "$upload_response" | grep -o '"app_url":"[^"]*' | cut -d'"' -f4)
123+
export BROWSERSTACK_APP=$app_url
124+
log_msg_to "Exported BROWSERSTACK_APP=$BROWSERSTACK_APP"
125+
126+
if [ -z "$app_url" ]; then
127+
log_msg_to "❌ Upload failed. Response: $UPLOAD_RESPONSE"
128+
return 1
129+
fi
130+
131+
log_msg_to "✅ App uploaded successfully: $app_url"
132+
return 0
133+
}
134+
135+
upload_custom_app() {
136+
local -n app_url=$1
137+
local -n platform=$2
138+
local app_platform=""
139+
local file_path
140+
file_path=$(osascript -e 'choose file with prompt "Select your .apk or .ipa file:" of type {"apk", "ipa"}' 2>/dev/null)
141+
142+
if [ -z "$file_path" ]; then
143+
log_msg_to "❌ No file selected"
144+
return 1
145+
fi
146+
147+
# Determine platform from file extension
148+
if [[ "$file_path" == *.ipa ]]; then
149+
platform="ios"
150+
app_platform="ios"
151+
elif [[ "$file_path" == *.apk ]]; then
152+
platform="android"
153+
app_platform="android"
154+
else
155+
log_msg_to "❌ Invalid file type. Must be .apk or .ipa"
156+
return 1
157+
fi
158+
159+
log_msg_to "⬆️ Uploading app to BrowserStack..."
160+
local upload_response
161+
upload_response=$(curl -s -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" \
162+
-X POST "https://api-cloud.browserstack.com/app-automate/upload" \
163+
-F "file=@$file_path")
164+
165+
app_url=$(echo "$upload_response" | grep -o '"app_url":"[^"]*' | cut -d'"' -f4)
166+
if [ -z "$app_url" ]; then
167+
log_msg_to "❌ Failed to upload app"
168+
return 1
169+
fi
170+
171+
export BROWSERSTACK_APP=$app_url
172+
log_msg_to "✅ App uploaded successfully"
173+
log_msg_to "Exported BROWSERSTACK_APP=$BROWSERSTACK_APP"
174+
175+
export APP_PLATFORM="$app_platform"
176+
log_msg_to "Exported APP_PLATFORM=$APP_PLATFORM"
177+
return 0
178+
}
179+
180+
# ===== Dynamic config generators =====
181+
generate_web_platforms() {
182+
local max_total_parallels=$1
183+
local platformsListContentFormat=$2
184+
local platform="web"
185+
export NOW_PLATFORM="$platform"
186+
local platformsList=$(pick_terminal_devices "$NOW_PLATFORM" $max_total_parallels "$platformsListContentFormat")
187+
echo "$platformsList"
188+
}
189+
190+
generate_mobile_platforms() {
191+
local max_total_parallels=$1
192+
local platformsListContentFormat=$2
193+
local app_platform="$APP_PLATFORM"
194+
local platformsList=$(pick_terminal_devices "$app_platform" $max_total_parallels, "$platformsListContentFormat")
195+
echo "$platformsList"
196+
}
197+
198+
199+
# ===== Fetch plan details (writes to GLOBAL) =====
200+
fetch_plan_details() {
201+
local test_type=$1
202+
203+
log_section "☁️ Account & Plan Details"
204+
log_info "Fetching BrowserStack plan for $test_type"
205+
local web_unauthorized=false
206+
local mobile_unauthorized=false
207+
208+
if [[ "$test_type" == "web" || "$test_type" == "both" ]]; then
209+
RESPONSE_WEB=$(curl -s -w "\n%{http_code}" -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" https://api.browserstack.com/automate/plan.json)
210+
HTTP_CODE_WEB=$(echo "$RESPONSE_WEB" | tail -n1)
211+
RESPONSE_WEB_BODY=$(echo "$RESPONSE_WEB" | sed '$d')
212+
if [ "$HTTP_CODE_WEB" == "200" ]; then
213+
WEB_PLAN_FETCHED=true
214+
TEAM_PARALLELS_MAX_ALLOWED_WEB=$(echo "$RESPONSE_WEB_BODY" | grep -o '"parallel_sessions_max_allowed":[0-9]*' | grep -o '[0-9]*')
215+
export TEAM_PARALLELS_MAX_ALLOWED_WEB="$TEAM_PARALLELS_MAX_ALLOWED_WEB"
216+
log_msg_to "✅ Web Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_WEB"
217+
else
218+
log_msg_to "❌ Web Testing Plan fetch failed ($HTTP_CODE_WEB)"
219+
[ "$HTTP_CODE_WEB" == "401" ] && web_unauthorized=true
220+
fi
221+
fi
222+
223+
if [[ "$test_type" == "app" || "$test_type" == "both" ]]; then
224+
RESPONSE_MOBILE=$(curl -s -w "\n%{http_code}" -u "$BROWSERSTACK_USERNAME:$BROWSERSTACK_ACCESS_KEY" https://api-cloud.browserstack.com/app-automate/plan.json)
225+
HTTP_CODE_MOBILE=$(echo "$RESPONSE_MOBILE" | tail -n1)
226+
RESPONSE_MOBILE_BODY=$(echo "$RESPONSE_MOBILE" | sed '$d')
227+
if [ "$HTTP_CODE_MOBILE" == "200" ]; then
228+
MOBILE_PLAN_FETCHED=true
229+
TEAM_PARALLELS_MAX_ALLOWED_MOBILE=$(echo "$RESPONSE_MOBILE_BODY" | grep -o '"parallel_sessions_max_allowed":[0-9]*' | grep -o '[0-9]*')
230+
export TEAM_PARALLELS_MAX_ALLOWED_MOBILE="$TEAM_PARALLELS_MAX_ALLOWED_MOBILE"
231+
log_msg_to "✅ Mobile App Testing Plan fetched: Team max parallel sessions = $TEAM_PARALLELS_MAX_ALLOWED_MOBILE"
232+
else
233+
log_msg_to "❌ Mobile App Testing Plan fetch failed ($HTTP_CODE_MOBILE)"
234+
[ "$HTTP_CODE_MOBILE" == "401" ] && mobile_unauthorized=true
235+
fi
236+
fi
237+
238+
log_info "Plan summary: Web $WEB_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_WEB max), Mobile $MOBILE_PLAN_FETCHED ($TEAM_PARALLELS_MAX_ALLOWED_MOBILE max)"
239+
240+
if [[ "$test_type" == "web" && "$web_unauthorized" == true ]] || \
241+
[[ "$test_type" == "app" && "$mobile_unauthorized" == true ]] || \
242+
[[ "$test_type" == "both" && "$web_unauthorized" == true && "$mobile_unauthorized" == true ]]; then
243+
log_msg_to "❌ Unauthorized to fetch required plan(s). Exiting."
244+
exit 1
245+
fi
246+
}
247+
248+
# Function to check if IP is private
249+
is_private_ip() {
250+
case $1 in
251+
10.* | 192.168.* | 172.16.* | 172.17.* | 172.18.* | 172.19.* | \
252+
172.20.* | 172.21.* | 172.22.* | 172.23.* | 172.24.* | 172.25.* | \
253+
172.26.* | 172.27.* | 172.28.* | 172.29.* | 172.30.* | 172.31.* | "")
254+
return 0 ;; # Private
255+
*)
256+
return 1 ;; # Public
257+
esac
258+
}
259+
260+
is_domain_private() {
261+
domain=${CX_TEST_URL#*://} # remove protocol
262+
domain=${domain%%/*} # remove everything after first "/"
263+
log_msg_to "Website domain: $domain"
264+
export NOW_WEB_DOMAIN="$CX_TEST_URL"
265+
266+
# Resolve domain using Cloudflare DNS
267+
IP_ADDRESS=$(dig +short "$domain" @1.1.1.1 | head -n1)
268+
269+
# Determine if domain is private
270+
if is_private_ip "$IP_ADDRESS"; then
271+
is_cx_domain_private=0
272+
else
273+
is_cx_domain_private=-1
274+
fi
275+
276+
log_msg_to "Resolved IPs: $IP_ADDRESS"
277+
278+
return $is_cx_domain_private
279+
}
280+
281+
282+
identify_run_status_java() {
283+
local log_file=$1
284+
log_section "✅ Results"
285+
286+
# Extract the test summary line
287+
local line=$(grep -m 2 -E "[INFO|ERROR].*Tests run" < "$log_file")
288+
# If not found, fail
289+
if [[ -z "$line" ]]; then
290+
log_warn "❌ No test summary line found."
291+
return 1
292+
fi
293+
294+
# Extract numbers using regex
295+
tests_run=$(echo "$line" | grep -m 1 -oE "Tests run: [0-9]+" | awk '{print $3}')
296+
failures=$(echo "$line" | grep -m 1 -oE "Failures: [0-9]+" | awk '{print $2}')
297+
errors=$(echo "$line" | grep -m 1 -oE "Errors: [0-9]+" | awk '{print $2}')
298+
skipped=$(echo "$line" | grep -m 1 -oE "Skipped: [0-9]+" | awk '{print $2}')
299+
300+
# Calculate passed tests
301+
passed=$(( $tests_run - ($failures + $errors + $skipped) ))
302+
303+
# Check condition
304+
if (( passed > 0 )); then
305+
log_success "Success: $passed test(s) passed."
306+
return 0
307+
else
308+
log_error "Error: No tests passed (Tests run: $tests_run, Failures: $failures, Errors: $errors, Skipped: $skipped)"
309+
return 1
310+
fi
311+
312+
return 1
313+
}
314+
315+
316+
identify_run_status_nodejs() {
317+
318+
local log_file=$1
319+
log_info "Identifying run status"
320+
local line=$(grep -m 1 -E "Spec Files:.*passed.*total" < "$log_file")
321+
# If not found, fail
322+
if [[ -z "$line" ]]; then
323+
log_warn "❌ No test summary line found."
324+
return 1
325+
fi
326+
327+
# Extract numbers using regex
328+
passed=$(echo "$line" | grep -oE '[0-9]+ passed' | awk '{print $1}')
329+
# Check condition
330+
if (( passed > 0 )); then
331+
log_success "Success: $passed test(s) passed"
332+
return 0
333+
else
334+
log_error "❌ Error: No tests passed"
335+
return 1
336+
fi
337+
338+
return 1
339+
}
340+
341+
342+
identify_run_status_python() {
343+
344+
local log_file=$1
345+
log_info "Identifying run status"
346+
347+
# Extract numbers and sum them
348+
passed_sum=$(grep -oE '[0-9]+ passed' "$log_file" | awk '{sum += $1} END {print sum+0}')
349+
350+
echo "✅ Total Passed: $passed_sum"
351+
352+
local completed_test_count=passed_sum+warning_sum
353+
354+
# If not found, fail
355+
if [[ -z "$passed_sum" ]]; then
356+
log_warn "❌ No test summary line found."
357+
return 1
358+
fi
359+
360+
# Check condition
361+
if (( passed_sum > 0 )); then
362+
log_success "Success: $passed_sum test(s) completed"
363+
return 0
364+
else
365+
log_error "❌ Error: No tests completed"
366+
return 1
367+
fi
368+
369+
return 1
370+
}
371+
372+
clear_old_logs() {
373+
mkdir -p "$LOG_DIR"
374+
: > "$NOW_RUN_LOG_FILE"
375+
376+
log_success "Logs cleared and fresh run initiated."
377+
}

0 commit comments

Comments
 (0)