@freshworks/shiftleft-tools 1.1.14 → 1.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1,35 +1,23 @@
1
1
  #!/usr/bin/env bash
2
2
 
3
3
  ###############################################################################
4
- # Staging Test Runner
4
+ # Staging Test Runner (generic)
5
5
  #
6
- # Runs API tests against staging environment with automatic JWT generation.
6
+ # Runs Postman/Newman API tests against a staging environment, with automatic
7
+ # JWT generation from a secret stored in AWS Secrets Manager.
7
8
  #
8
9
  # Usage:
9
- # ./run-tests-staging.sh # Run V3 + V2 tests (Legacy skipped)
10
- # ./run-tests-staging.sh --v3 # Run only V3 tests
11
- # ./run-tests-staging.sh --v2 # Run only V2 tests
12
- # ./run-tests-staging.sh --legacy # Run only Legacy tests
13
- # ./run-tests-staging.sh --multi-product # Run V3 tests across all products
14
- # ./run-tests-staging.sh --help # Show this help
15
- #
16
- # Note: Legacy API tests are SKIPPED by default in staging.
17
- # Multi-Product Testing:
18
- # Tests V3 APIs (CRUD + Files) across Freshdesk, Freshservice, and Freshworks CRM
19
- # Requires product-specific environment files in postman/environments/:
20
- # - staging-freshdesk.postman_environment.json
21
- # - staging-freshservice.postman_environment.json
22
- # - staging-freshworks_crm.postman_environment.json
10
+ # AWS_PROFILE=staging ./run-tests-staging.sh # Run all collections
11
+ # ./run-tests-staging.sh --help # Show this help
23
12
  #
24
13
  # Prerequisites:
25
14
  # - AWS CLI configured (set AWS_PROFILE for local use)
26
- # - jq installed
27
- # - Node.js installed
15
+ # - jq, Node.js installed
16
+ # - postman/config/staging.json present (aws.*, base_url, jwt.*)
28
17
  #
29
- # Examples:
30
- # AWS_PROFILE=staging ./run-tests-staging.sh
31
- # ./run-tests-staging.sh --v3 # Quick V3 test only
32
- # ./run-tests-staging.sh --multi-product # Test all products
18
+ # This runner ships generic. The /setup-api-tests skill fills the repo-specific
19
+ # blocks below (marked `repo-specific`) and then runs `shiftleft protect` so
20
+ # `shiftleft test` staging never overwrites your customizations.
33
21
  ###############################################################################
34
22
 
35
23
  set -e
@@ -40,150 +28,60 @@ PROJECT_ROOT="$(cd "$SCRIPT_DIR/../.." && pwd)"
40
28
  REPORT_LOGO="${SHIFTLEFT_REPORT_LOGO:-$(basename "$PROJECT_ROOT")}"
41
29
  POSTMAN_DIR="$PROJECT_ROOT/postman"
42
30
 
43
- # Configuration
44
31
  CONFIG_FILE="$POSTMAN_DIR/config/staging.json"
45
32
  REPORT_DIR="$POSTMAN_DIR/reports"
46
33
  TIMESTAMP=$(date +%Y%m%d-%H%M%S)
47
34
 
48
- # Collections
49
- # Collections (now split into multiple files by folder)
50
- CRUD_COLLECTIONS_DIR="$POSTMAN_DIR/collections/crud"
51
- FILES_COLLECTIONS_DIR="$POSTMAN_DIR/collections/files"
52
- V2_COLLECTIONS_DIR="$POSTMAN_DIR/collections/v2"
53
- LEGACY_COLLECTIONS_DIR="$POSTMAN_DIR/collections/legacy"
35
+ COLLECTIONS_DIR="$POSTMAN_DIR/collections"
54
36
  ENVIRONMENT="$POSTMAN_DIR/environments/staging.postman_environment.json"
55
37
 
56
- # Parse arguments
57
- RUN_V3=false
58
- RUN_V2=false
59
- RUN_LEGACY=false
60
38
  SHOW_HELP=false
61
- MULTI_PRODUCT=false
62
- RUN_ALL=true
63
-
64
- # Multi-product configuration
65
- PRODUCTS="freshdesk freshservice freshworks-crm"
66
- declare -A PRODUCT_DISPLAY_NAMES
67
- PRODUCT_DISPLAY_NAMES["freshdesk"]="Freshdesk"
68
- PRODUCT_DISPLAY_NAMES["freshservice"]="Freshservice"
69
- PRODUCT_DISPLAY_NAMES["freshworks-crm"]="Freshworks CRM"
70
- declare -A PRODUCT_IDS
71
- PRODUCT_IDS["freshdesk"]="9"
72
- PRODUCT_IDS["freshservice"]="3"
73
- PRODUCT_IDS["freshworks-crm"]="39"
74
- declare -A PRODUCT_NAMES
75
- PRODUCT_NAMES["freshdesk"]="freshdesk"
76
- PRODUCT_NAMES["freshservice"]="freshservice"
77
- PRODUCT_NAMES["freshworks-crm"]="freshworks_crm"
78
- declare -A PRODUCT_FILE_IDS
79
- PRODUCT_FILE_IDS["freshdesk"]="staging_fd_external_file_123"
80
- PRODUCT_FILE_IDS["freshservice"]="staging_fs_external_file_123"
81
- PRODUCT_FILE_IDS["freshworks-crm"]="staging_crm_external_file_123"
82
-
83
- # Per-collection status tracking
84
- declare -A COLLECTION_STATUS
85
- declare -A COLLECTION_PASSED
86
- declare -A COLLECTION_FAILED
87
-
88
- # For multi-product, we track per product-collection
89
- # For single product, we track per collection
90
- COLLECTION_STATUS["V3_CRUD"]="Not Run"
91
- COLLECTION_STATUS["V3_FILES"]="Not Run"
92
- COLLECTION_STATUS["V2"]="Not Run"
93
- COLLECTION_STATUS["LEGACY"]="Not Run"
94
- COLLECTION_PASSED["V3_CRUD"]=0
95
- COLLECTION_PASSED["V3_FILES"]=0
96
- COLLECTION_PASSED["V2"]=0
97
- COLLECTION_PASSED["LEGACY"]=0
98
- COLLECTION_FAILED["V3_CRUD"]=0
99
- COLLECTION_FAILED["V3_FILES"]=0
100
- COLLECTION_FAILED["V2"]=0
101
- COLLECTION_FAILED["LEGACY"]=0
102
-
103
- # Multi-product tracking
104
- declare -A PRODUCT_STATUS
105
- PRODUCT_STATUS["freshdesk"]="Not Run"
106
- PRODUCT_STATUS["freshservice"]="Not Run"
107
- PRODUCT_STATUS["freshworks-crm"]="Not Run"
108
-
109
39
  for arg in "$@"; do
110
40
  case $arg in
111
- --v3)
112
- RUN_V3=true
113
- RUN_ALL=false
114
- ;;
115
- --v2)
116
- RUN_V2=true
117
- RUN_ALL=false
118
- ;;
119
- --legacy)
120
- RUN_LEGACY=true
121
- RUN_ALL=false
122
- ;;
123
- --multi-product)
124
- MULTI_PRODUCT=true
125
- RUN_V3=true
126
- RUN_ALL=false
127
- ;;
128
- --help|-h)
129
- SHOW_HELP=true
130
- ;;
41
+ --help|-h) SHOW_HELP=true ;;
131
42
  esac
132
43
  done
133
-
134
44
  if [ "$SHOW_HELP" = true ]; then
135
- head -33 "$0" | tail -30
45
+ head -21 "$0" | tail -18
136
46
  exit 0
137
47
  fi
138
48
 
139
- if [ "$RUN_ALL" = true ]; then
140
- RUN_V3=true
141
- RUN_V2=true
142
- # Skip Legacy tests in staging by default - they run locally via WireMock.
143
- RUN_LEGACY=false
144
- fi
49
+ #==============================================================================
50
+ # STATE + HELPERS
51
+ #==============================================================================
52
+
53
+ TOTAL_PASSED=0
54
+ TOTAL_FAILED=0
55
+ declare -a RESULTS
56
+ declare -A COLLECTION_STATUS
57
+ declare -A COLLECTION_PASSED
58
+ declare -A COLLECTION_FAILED
59
+
60
+ parse_newman_results() {
61
+ local output_file="$1"
62
+ local assertions_line=$(grep "assertions" "$output_file" 2>/dev/null | head -1)
63
+ NEWMAN_EXECUTED=$(echo "$assertions_line" | awk -F'│' '{gsub(/[^0-9]/,"",$3); print $3}')
64
+ NEWMAN_FAILED=$(echo "$assertions_line" | awk -F'│' '{gsub(/[^0-9]/,"",$4); print $4}')
65
+ NEWMAN_EXECUTED=${NEWMAN_EXECUTED:-0}
66
+ NEWMAN_FAILED=${NEWMAN_FAILED:-0}
67
+ NEWMAN_PASSED=$((NEWMAN_EXECUTED > 0 ? NEWMAN_EXECUTED - NEWMAN_FAILED : 0))
68
+ }
145
69
 
146
70
  echo "========================================="
147
- if [ "$MULTI_PRODUCT" = true ]; then
148
- echo "${REPORT_LOGO} Staging Tests (Multi-Product)"
149
- else
150
- echo "${REPORT_LOGO} Staging Tests"
151
- fi
71
+ echo "${REPORT_LOGO} Staging Tests"
152
72
  echo "========================================="
153
73
  echo ""
154
- if [ "$MULTI_PRODUCT" = true ]; then
155
- echo "Mode: Multi-Product Testing"
156
- echo "Products:"
157
- echo " - Freshdesk (product_id: 9)"
158
- echo " - Freshservice (product_id: 3)"
159
- echo " - Freshworks CRM (product_id: 39)"
160
- echo ""
161
- echo "Test Suites: V3 API (CRUD + Files) for each product"
162
- else
163
- echo "Test Suites:"
164
- [ "$RUN_V3" = true ] && echo " ✓ V3 API (CRUD + Files)"
165
- [ "$RUN_V2" = true ] && echo " ✓ V2 API (OAuth, Transfer)"
166
- [ "$RUN_LEGACY" = true ] && echo " ✓ Legacy API"
167
- [ "$RUN_LEGACY" = false ] && echo " ⊘ Legacy API (skipped)"
168
- fi
169
- echo ""
170
74
 
171
- # Check prerequisites
75
+ # Prerequisites
172
76
  echo "Checking prerequisites..."
173
- command -v jq >/dev/null 2>&1 || { echo "Error: jq required" >&2; exit 1; }
174
- command -v aws >/dev/null 2>&1 || { echo "Error: AWS CLI required" >&2; exit 1; }
77
+ command -v jq >/dev/null 2>&1 || { echo "Error: jq required" >&2; exit 1; }
78
+ command -v aws >/dev/null 2>&1 || { echo "Error: AWS CLI required" >&2; exit 1; }
175
79
  command -v node >/dev/null 2>&1 || { echo "Error: Node.js required" >&2; exit 1; }
176
-
177
- if [ ! -f "$CONFIG_FILE" ]; then
178
- echo "Error: Config file not found: $CONFIG_FILE"
179
- exit 1
180
- fi
181
-
182
-
80
+ [ -f "$CONFIG_FILE" ] || { echo "Error: Config file not found: $CONFIG_FILE" >&2; exit 1; }
183
81
  echo "✓ Prerequisites OK"
184
82
  echo ""
185
83
 
186
- # Load configuration
84
+ # Step 1: Load configuration
187
85
  echo "========================================="
188
86
  echo "Step 1: Loading Configuration"
189
87
  echo "========================================="
@@ -195,18 +93,16 @@ BASE_URL=$(jq -r '.base_url' "$CONFIG_FILE")
195
93
  echo " Base URL: $BASE_URL"
196
94
  echo ""
197
95
 
198
- # Fetch JWT secret from AWS
96
+ # Step 2: Fetch JWT secret from AWS
199
97
  echo "========================================="
200
98
  echo "Step 2: Fetching JWT Secret from AWS"
201
99
  echo "========================================="
202
100
  JWT_SECRET=$("$SCRIPT_DIR/../auth/get-aws-secret.sh" "$AWS_SECRET_NAME" "$AWS_CLIENT" "$AWS_ISSUER" "$AWS_REGION") || {
203
- echo "Error: Failed to fetch JWT secret"
204
- exit 1
205
- }
101
+ echo "Error: Failed to fetch JWT secret" >&2; exit 1; }
206
102
  echo "✓ JWT secret fetched"
207
103
  echo ""
208
104
 
209
- # Generate JWT token
105
+ # Step 3: Generate JWT token
210
106
  echo "========================================="
211
107
  echo "Step 3: Generating JWT Token"
212
108
  echo "========================================="
@@ -218,23 +114,20 @@ export API_USER_ID=$(jq -r '.jwt.api_user_id' "$CONFIG_FILE")
218
114
  export API_PRODUCT=$(jq -r '.jwt.api_product' "$CONFIG_FILE")
219
115
  export API_PRODUCT_ID=$(jq -r '.jwt.api_product_id' "$CONFIG_FILE")
220
116
  export API_USER_ROLE=$(jq -r '.jwt.api_user_role' "$CONFIG_FILE")
221
- export API_POD=$(jq -r '.jwt.api_pod' "$CONFIG_FILE")
222
- export API_SKUS=$(jq -r '.jwt.api_skus' "$CONFIG_FILE")
223
- export SKU=$(jq -r '.jwt.sku' "$CONFIG_FILE")
224
- export IS_SOURCE_INTERNAL=$(jq -r '.jwt.is_source_internal' "$CONFIG_FILE")
225
- export ORGANISATION_ID=$(jq -r '.jwt.organisation_id' "$CONFIG_FILE")
226
- export FRESHID_ACCOUNT_ID=$(jq -r '.jwt.freshid_account_id' "$CONFIG_FILE")
227
117
  export API_JWT_EXPIRY=$(jq -r '.jwt.api_jwt_expiry' "$CONFIG_FILE")
118
+ # >>> repo-specific (set by /setup-api-tests): extra JWT payload fields <<<
119
+ # Export any additional .jwt.* fields generate-jwt.sh needs, e.g.:
120
+ # export ORGANISATION_ID=$(jq -r '.jwt.organisation_id' "$CONFIG_FILE")
121
+ # export FRESHID_ACCOUNT_ID=$(jq -r '.jwt.freshid_account_id' "$CONFIG_FILE")
122
+ # <<< repo-specific >>>
228
123
 
229
124
  JWT_TOKEN=$("$SCRIPT_DIR/../auth/generate-jwt.sh") || {
230
- echo "Error: Failed to generate JWT token"
231
- exit 1
232
- }
125
+ echo "Error: Failed to generate JWT token" >&2; exit 1; }
233
126
  unset JWT_SECRET # Clear secret immediately
234
127
  echo "✓ JWT token generated"
235
128
  echo ""
236
129
 
237
- # Install Newman
130
+ # Step 4: Install Newman
238
131
  echo "========================================="
239
132
  echo "Step 4: Installing Newman"
240
133
  echo "========================================="
@@ -243,83 +136,58 @@ npm ci --ignore-scripts --silent 2>/dev/null || npm install --ignore-scripts --s
243
136
  echo "✓ Newman ready"
244
137
  echo ""
245
138
 
246
- mkdir -p "$REPORT_DIR"
247
- mkdir -p "$REPORT_DIR/json"
248
-
249
- # Test parameters from config
250
- EXTENSION_ID=$(jq -r '.test_data.extension_id' "$CONFIG_FILE")
251
- VERSION_ID=$(jq -r '.test_data.version_id' "$CONFIG_FILE")
252
- EXTENSION_TYPE=$(jq -r '.test_data.extension_type' "$CONFIG_FILE")
253
-
254
- # Initialize results
255
- TOTAL_PASSED=0
256
- TOTAL_FAILED=0
257
- declare -a RESULTS
258
-
259
- # Parse Newman output to extract assertion counts
260
- # Newman outputs a table like: │ assertions │ 20 │ 0 │
261
- parse_newman_results() {
262
- local output_file="$1"
263
- local assertions_line=$(grep "assertions" "$output_file" 2>/dev/null | head -1)
264
-
265
- NEWMAN_EXECUTED=$(echo "$assertions_line" | awk -F'│' '{gsub(/[^0-9]/,"",$3); print $3}')
266
- NEWMAN_FAILED=$(echo "$assertions_line" | awk -F'│' '{gsub(/[^0-9]/,"",$4); print $4}')
267
-
268
- NEWMAN_EXECUTED=${NEWMAN_EXECUTED:-0}
269
- NEWMAN_FAILED=${NEWMAN_FAILED:-0}
270
- NEWMAN_PASSED=$((NEWMAN_EXECUTED > 0 ? NEWMAN_EXECUTED - NEWMAN_FAILED : 0))
271
- }
139
+ mkdir -p "$REPORT_DIR" "$REPORT_DIR/json"
140
+
141
+ # Newman --env-var pairs injected into every collection run. Generic baseline;
142
+ # extend in the repo-specific block for app-specific variables.
143
+ NEWMAN_ENV_VARS=(
144
+ --env-var "auth_token=$JWT_TOKEN"
145
+ --env-var "base_url=$BASE_URL"
146
+ --env-var "product_id=$API_PRODUCT_ID"
147
+ --env-var "account_id=$API_ACCOUNT_ID"
148
+ --env-var "user_role=$API_USER_ROLE"
149
+ )
150
+ # >>> repo-specific (set by /setup-api-tests): extra newman --env-var pairs <<<
151
+ # e.g. NEWMAN_ENV_VARS+=( --env-var "extension_id=$(jq -r '.test_data.extension_id' "$CONFIG_FILE")" )
152
+ # <<< repo-specific >>>
153
+
154
+ #==============================================================================
155
+ # TEST EXECUTION
156
+ #==============================================================================
272
157
 
273
- # Helper function to run all collections in a directory
274
158
  run_collection_dir() {
275
159
  local dir_name="$1"
276
160
  local collections_dir="$2"
277
161
  local report_prefix="$3"
278
162
  local collection_key="$4"
279
-
163
+
280
164
  echo "========================================="
281
165
  echo "Running: $dir_name"
282
166
  echo "========================================="
283
-
167
+
284
168
  local dir_passed=0
285
169
  local dir_failed=0
286
170
  local all_passed=true
287
-
288
- # Create a working copy of the environment file to chain variables between collections
289
171
  local working_env="/tmp/newman-staging-env-${collection_key}.json"
290
172
  cp "$ENVIRONMENT" "$working_env"
291
-
292
- # Run collections in numerical order
173
+
174
+ shopt -s nullglob
293
175
  for collection_file in "$collections_dir"/*.json; do
294
- if [ ! -f "$collection_file" ]; then
295
- continue
296
- fi
297
-
176
+ [ ! -f "$collection_file" ] && continue
177
+
298
178
  local basename=$(basename "$collection_file" .json)
299
179
  local report_name="${report_prefix}-${basename}"
300
-
301
- echo ""
302
- echo " → Running: $basename"
303
- echo ""
304
-
305
180
  local html_report="$REPORT_DIR/$report_name-staging-$TIMESTAMP.html"
306
181
  local json_report="$REPORT_DIR/json/$report_name-staging-$TIMESTAMP.json"
307
182
  local env_export="/tmp/newman-env-export-staging-${basename}.json"
308
-
309
- if "$POSTMAN_DIR/node_modules/.bin/newman" run "$collection_file" \
183
+
184
+ echo ""
185
+ echo " → Running: $basename"
186
+ echo ""
187
+
188
+ "$POSTMAN_DIR/node_modules/.bin/newman" run "$collection_file" \
310
189
  --environment "$working_env" \
311
- --env-var "auth_token=$JWT_TOKEN" \
312
- --env-var "base_url=$BASE_URL" \
313
- --env-var "base_url_v2=${BASE_URL%/api/v3}/api/v2" \
314
- --env-var "legacy_base_url=${BASE_URL%/api/v3}" \
315
- --env-var "extension_id=$EXTENSION_ID" \
316
- --env-var "version_id=$VERSION_ID" \
317
- --env-var "extension_type=$EXTENSION_TYPE" \
318
- --env-var "product_id=$API_PRODUCT_ID" \
319
- --env-var "account_id=$API_ACCOUNT_ID" \
320
- --env-var "organisation_id=$ORGANISATION_ID" \
321
- --env-var "freshid_account_id=$FRESHID_ACCOUNT_ID" \
322
- --env-var "user_role=$API_USER_ROLE" \
190
+ "${NEWMAN_ENV_VARS[@]}" \
323
191
  --reporters cli,htmlextra,json \
324
192
  --reporter-htmlextra-export "$html_report" \
325
193
  --reporter-htmlextra-title "${REPORT_LOGO} - $dir_name - $basename (Staging)" \
@@ -327,41 +195,25 @@ run_collection_dir() {
327
195
  --reporter-json-export "$json_report" \
328
196
  --export-environment "$env_export" \
329
197
  --timeout-request 30000 \
330
- --delay-request 200 2>&1 | tee /tmp/newman-output.txt; then
331
-
332
- # Extract pass/fail counts using proper parser
333
- parse_newman_results /tmp/newman-output.txt
334
-
335
- dir_passed=$((dir_passed + NEWMAN_PASSED))
336
- dir_failed=$((dir_failed + NEWMAN_FAILED))
337
-
338
- # Update working environment for next collection (chain variables like installation_id)
339
- if [ -f "$env_export" ]; then
340
- cp "$env_export" "$working_env"
341
- fi
342
-
343
- echo " ✓ $basename: PASSED ($NEWMAN_PASSED passed, $NEWMAN_FAILED failed)"
344
- else
345
- # Extract counts even on failure using proper parser
346
- parse_newman_results /tmp/newman-output.txt
347
-
348
- dir_passed=$((dir_passed + NEWMAN_PASSED))
349
- dir_failed=$((dir_failed + NEWMAN_FAILED))
350
- all_passed=false
351
-
352
- # Update working environment even on failure (to preserve any variables set)
353
- if [ -f "$env_export" ]; then
354
- cp "$env_export" "$working_env"
355
- fi
356
-
198
+ --delay-request 200 2>&1 | tee /tmp/newman-output.txt || true
199
+
200
+ parse_newman_results /tmp/newman-output.txt
201
+ dir_passed=$((dir_passed + NEWMAN_PASSED))
202
+ dir_failed=$((dir_failed + NEWMAN_FAILED))
203
+ [ "$NEWMAN_FAILED" -gt 0 ] && all_passed=false
204
+
205
+ [ -f "$env_export" ] && cp "$env_export" "$working_env"
206
+
207
+ if [ "$NEWMAN_FAILED" -gt 0 ]; then
357
208
  echo " ✗ $basename: FAILED ($NEWMAN_PASSED passed, $NEWMAN_FAILED failed)"
209
+ else
210
+ echo " ✓ $basename: PASSED ($NEWMAN_PASSED passed, $NEWMAN_FAILED failed)"
358
211
  fi
359
212
  done
360
-
361
- # Cleanup temporary environment files
213
+ shopt -u nullglob
214
+
362
215
  rm -f "$working_env" /tmp/newman-env-export-staging-*.json
363
-
364
- # Update collection status
216
+
365
217
  if [ "$all_passed" = true ] && [ "$dir_failed" -eq 0 ]; then
366
218
  COLLECTION_STATUS["$collection_key"]="✓ PASSED"
367
219
  RESULTS+=("$dir_name: ✓ PASSED ($dir_passed passed, $dir_failed failed)")
@@ -373,369 +225,64 @@ run_collection_dir() {
373
225
  echo ""
374
226
  echo "✗ $dir_name: SOME FAILED"
375
227
  fi
376
-
228
+
377
229
  COLLECTION_PASSED["$collection_key"]=$dir_passed
378
230
  COLLECTION_FAILED["$collection_key"]=$dir_failed
379
231
  TOTAL_PASSED=$((TOTAL_PASSED + dir_passed))
380
232
  TOTAL_FAILED=$((TOTAL_FAILED + dir_failed))
381
-
382
- [ "$all_passed" = true ] && [ "$dir_failed" -eq 0 ]
383
233
  }
384
234
 
385
- # Run collection helper
386
- run_collection() {
387
- local name="$1"
388
- local collection="$2"
389
- local report_name="$3"
390
- local collection_key="$4" # Key for status tracking
391
-
392
- echo "========================================="
393
- echo "Running: $name"
394
- echo "========================================="
395
-
396
- local html_report="$REPORT_DIR/$report_name-staging-$TIMESTAMP.html"
397
- local json_report="$REPORT_DIR/json/$report_name-staging-$TIMESTAMP.json"
398
-
399
- if "$POSTMAN_DIR/node_modules/.bin/newman" run "$collection" \
400
- --environment "$ENVIRONMENT" \
401
- --env-var "auth_token=$JWT_TOKEN" \
402
- --env-var "base_url=$BASE_URL" \
403
- --env-var "base_url_v2=${BASE_URL%/api/v3}/api/v2" \
404
- --env-var "legacy_base_url=${BASE_URL%/api/v3}" \
405
- --env-var "extension_id=$EXTENSION_ID" \
406
- --env-var "version_id=$VERSION_ID" \
407
- --env-var "extension_type=$EXTENSION_TYPE" \
408
- --env-var "product_id=$API_PRODUCT_ID" \
409
- --env-var "account_id=$API_ACCOUNT_ID" \
410
- --env-var "organisation_id=$ORGANISATION_ID" \
411
- --env-var "freshid_account_id=$FRESHID_ACCOUNT_ID" \
412
- --env-var "user_role=$API_USER_ROLE" \
413
- --reporters cli,htmlextra,json \
414
- --reporter-htmlextra-export "$html_report" \
415
- --reporter-htmlextra-title "${REPORT_LOGO} - $name (Staging)" \
416
- --reporter-htmlextra-darkTheme \
417
- --reporter-json-export "$json_report" \
418
- --timeout-request 30000 \
419
- --delay-request 200 2>&1 | tee /tmp/newman-output.txt; then
420
-
421
- # Extract pass/fail counts using proper parser
422
- parse_newman_results /tmp/newman-output.txt
423
-
424
- echo "✓ $name: PASSED"
425
- RESULTS+=("$name: ✓ PASSED ($NEWMAN_PASSED passed, $NEWMAN_FAILED failed)")
426
- COLLECTION_STATUS["$collection_key"]="✓ PASSED"
427
- COLLECTION_PASSED["$collection_key"]=$NEWMAN_PASSED
428
- COLLECTION_FAILED["$collection_key"]=$NEWMAN_FAILED
429
- TOTAL_PASSED=$((TOTAL_PASSED + NEWMAN_PASSED))
430
- TOTAL_FAILED=$((TOTAL_FAILED + NEWMAN_FAILED))
431
- return 0
432
- else
433
- # Extract counts even on failure using proper parser
434
- parse_newman_results /tmp/newman-output.txt
435
-
436
- echo "✗ $name: FAILED"
437
- RESULTS+=("$name: ✗ FAILED ($NEWMAN_PASSED passed, $NEWMAN_FAILED failed)")
438
- COLLECTION_STATUS["$collection_key"]="✗ FAILED"
439
- COLLECTION_PASSED["$collection_key"]=$NEWMAN_PASSED
440
- COLLECTION_FAILED["$collection_key"]=$NEWMAN_FAILED
441
- TOTAL_PASSED=$((TOTAL_PASSED + NEWMAN_PASSED))
442
- TOTAL_FAILED=$((TOTAL_FAILED + NEWMAN_FAILED))
443
- return 1
444
- fi
445
- }
446
-
447
- # Run tests
448
- echo ""
449
-
450
- if [ "$MULTI_PRODUCT" = true ]; then
451
- # Multi-product mode: Run V3 tests for each product
452
- for product in $PRODUCTS; do
453
- echo ""
454
- echo "========================================="
455
- echo "Testing Product: $product"
456
- echo "========================================="
457
-
458
- # Use base staging environment, override product-specific vars
459
- PRODUCT_JWT_TOKEN="$JWT_TOKEN"
460
- PRODUCT_ID="${PRODUCT_IDS[$product]}"
461
- PRODUCT_NAME="${PRODUCT_NAMES[$product]}"
462
- PRODUCT_FILE_ID="${PRODUCT_FILE_IDS[$product]}"
463
-
464
- PRODUCT_PASSED=true
465
-
466
- # Each product gets its own report subdirectory
467
- PRODUCT_REPORT_DIR="$REPORT_DIR/${product}"
468
- PRODUCT_JSON_DIR="$REPORT_DIR/json/${product}"
469
- mkdir -p "$PRODUCT_REPORT_DIR" "$PRODUCT_JSON_DIR"
470
-
471
- # Working env copy for chaining variables between collections
472
- PRODUCT_WORKING_ENV="/tmp/newman-staging-env-${product}-${TIMESTAMP}.json"
473
- cp "$ENVIRONMENT" "$PRODUCT_WORKING_ENV"
474
-
475
- # Run CRUD tests for this product
476
- crud_key="${product}_CRUD"
477
- COLLECTION_STATUS["$crud_key"]="Not Run"
478
- COLLECTION_PASSED["$crud_key"]=0
479
- COLLECTION_FAILED["$crud_key"]=0
480
- CRUD_PASSED=0; CRUD_FAILED=0; CRUD_ALL_PASSED=true
481
-
482
- echo ""
483
- echo "Running CRUD API tests for $product..."
484
- for collection_file in "$CRUD_COLLECTIONS_DIR"/*.json; do
485
- [ ! -f "$collection_file" ] && continue
486
- basename=$(basename "$collection_file" .json)
487
- REPORT_FILE="$PRODUCT_REPORT_DIR/crud-${basename}-$TIMESTAMP.html"
488
- JSON_REPORT="$PRODUCT_JSON_DIR/crud-${basename}-$TIMESTAMP.json"
489
- ENV_EXPORT="/tmp/newman-env-export-staging-${product}-crud-${basename}.json"
490
- echo " → $basename"
491
- "$POSTMAN_DIR/node_modules/.bin/newman" run "$collection_file" \
492
- --environment "$PRODUCT_WORKING_ENV" \
493
- --env-var "auth_token=$PRODUCT_JWT_TOKEN" \
494
- --env-var "base_url=$BASE_URL" \
495
- --env-var "base_url_v2=${BASE_URL%/api/v3}/api/v2" \
496
- --env-var "legacy_base_url=${BASE_URL%/api/v3}" \
497
- --env-var "extension_id=$EXTENSION_ID" \
498
- --env-var "version_id=$VERSION_ID" \
499
- --env-var "extension_type=$EXTENSION_TYPE" \
500
- --env-var "product_id=$PRODUCT_ID" \
501
- --env-var "product_name=$PRODUCT_NAME" \
502
- --env-var "file_external_id=$PRODUCT_FILE_ID" \
503
- --env-var "account_id=$API_ACCOUNT_ID" \
504
- --env-var "organisation_id=$ORGANISATION_ID" \
505
- --env-var "freshid_account_id=$FRESHID_ACCOUNT_ID" \
506
- --env-var "user_role=$API_USER_ROLE" \
507
- --reporters cli,htmlextra,json \
508
- --reporter-htmlextra-export "$REPORT_FILE" \
509
- --reporter-htmlextra-title "${REPORT_LOGO} - $product - CRUD - $basename (Staging)" \
510
- --reporter-htmlextra-darkTheme \
511
- --reporter-json-export "$JSON_REPORT" \
512
- --export-environment "$ENV_EXPORT" \
513
- --timeout-request 30000 \
514
- --delay-request 200 2>&1 | tee /tmp/newman-output-${product}.txt
515
- parse_newman_results /tmp/newman-output-${product}.txt
516
- CRUD_PASSED=$((CRUD_PASSED + NEWMAN_PASSED))
517
- CRUD_FAILED=$((CRUD_FAILED + NEWMAN_FAILED))
518
- [ -f "$ENV_EXPORT" ] && cp "$ENV_EXPORT" "$PRODUCT_WORKING_ENV"
519
- [ "$NEWMAN_FAILED" -gt 0 ] && CRUD_ALL_PASSED=false
520
- done
521
- COLLECTION_PASSED["$crud_key"]=$CRUD_PASSED
522
- COLLECTION_FAILED["$crud_key"]=$CRUD_FAILED
523
- TOTAL_PASSED=$((TOTAL_PASSED + CRUD_PASSED))
524
- TOTAL_FAILED=$((TOTAL_FAILED + CRUD_FAILED))
525
- if [ "$CRUD_ALL_PASSED" = true ]; then
526
- echo "✓ CRUD tests passed for $product ($CRUD_PASSED passed, $CRUD_FAILED failed)"
527
- COLLECTION_STATUS["$crud_key"]="✓ PASSED"
528
- else
529
- echo "✗ CRUD tests failed for $product ($CRUD_PASSED passed, $CRUD_FAILED failed)"
530
- COLLECTION_STATUS["$crud_key"]="✗ FAILED"
531
- PRODUCT_PASSED=false
532
- fi
533
-
534
- # Run Files tests for this product
535
- files_key="${product}_FILES"
536
- COLLECTION_STATUS["$files_key"]="Not Run"
537
- COLLECTION_PASSED["$files_key"]=0
538
- COLLECTION_FAILED["$files_key"]=0
539
- FILES_PASSED=0; FILES_FAILED=0; FILES_ALL_PASSED=true
540
-
541
- echo ""
542
- echo "Running Files API tests for $product..."
543
- for collection_file in "$FILES_COLLECTIONS_DIR"/*.json; do
544
- [ ! -f "$collection_file" ] && continue
545
- basename=$(basename "$collection_file" .json)
546
- REPORT_FILE="$PRODUCT_REPORT_DIR/files-${basename}-$TIMESTAMP.html"
547
- JSON_REPORT="$PRODUCT_JSON_DIR/files-${basename}-$TIMESTAMP.json"
548
- ENV_EXPORT="/tmp/newman-env-export-staging-${product}-files-${basename}.json"
549
- echo " → $basename"
550
- "$POSTMAN_DIR/node_modules/.bin/newman" run "$collection_file" \
551
- --environment "$PRODUCT_WORKING_ENV" \
552
- --env-var "auth_token=$PRODUCT_JWT_TOKEN" \
553
- --env-var "base_url=$BASE_URL" \
554
- --env-var "base_url_v2=${BASE_URL%/api/v3}/api/v2" \
555
- --env-var "legacy_base_url=${BASE_URL%/api/v3}" \
556
- --env-var "extension_id=$EXTENSION_ID" \
557
- --env-var "version_id=$VERSION_ID" \
558
- --env-var "extension_type=$EXTENSION_TYPE" \
559
- --env-var "product_id=$PRODUCT_ID" \
560
- --env-var "product_name=$PRODUCT_NAME" \
561
- --env-var "file_external_id=$PRODUCT_FILE_ID" \
562
- --env-var "account_id=$API_ACCOUNT_ID" \
563
- --env-var "organisation_id=$ORGANISATION_ID" \
564
- --env-var "freshid_account_id=$FRESHID_ACCOUNT_ID" \
565
- --env-var "user_role=$API_USER_ROLE" \
566
- --reporters cli,htmlextra,json \
567
- --reporter-htmlextra-export "$REPORT_FILE" \
568
- --reporter-htmlextra-title "${REPORT_LOGO} - $product - Files - $basename (Staging)" \
569
- --reporter-htmlextra-darkTheme \
570
- --reporter-json-export "$JSON_REPORT" \
571
- --export-environment "$ENV_EXPORT" \
572
- --timeout-request 30000 \
573
- --delay-request 200 2>&1 | tee /tmp/newman-output-${product}.txt
574
- parse_newman_results /tmp/newman-output-${product}.txt
575
- FILES_PASSED=$((FILES_PASSED + NEWMAN_PASSED))
576
- FILES_FAILED=$((FILES_FAILED + NEWMAN_FAILED))
577
- [ -f "$ENV_EXPORT" ] && cp "$ENV_EXPORT" "$PRODUCT_WORKING_ENV"
578
- [ "$NEWMAN_FAILED" -gt 0 ] && FILES_ALL_PASSED=false
579
- done
580
- rm -f "$PRODUCT_WORKING_ENV" /tmp/newman-env-export-staging-${product}-*.json
581
- COLLECTION_PASSED["$files_key"]=$FILES_PASSED
582
- COLLECTION_FAILED["$files_key"]=$FILES_FAILED
583
- TOTAL_PASSED=$((TOTAL_PASSED + FILES_PASSED))
584
- TOTAL_FAILED=$((TOTAL_FAILED + FILES_FAILED))
585
- if [ "$FILES_ALL_PASSED" = true ]; then
586
- echo "✓ Files tests passed for $product ($FILES_PASSED passed, $FILES_FAILED failed)"
587
- COLLECTION_STATUS["$files_key"]="✓ PASSED"
588
- else
589
- echo "✗ Files tests failed for $product ($FILES_PASSED passed, $FILES_FAILED failed)"
590
- COLLECTION_STATUS["$files_key"]="✗ FAILED"
591
- PRODUCT_PASSED=false
592
- fi
593
-
594
- # Update product status
595
- if [ "$PRODUCT_PASSED" = true ]; then
596
- PRODUCT_STATUS["$product"]="✓ PASSED"
597
- else
598
- PRODUCT_STATUS["$product"]="✗ FAILED"
599
- fi
600
- done
235
+ # Generic single-suite run. Repos with versioned suites or multi-product
236
+ # testing extend this via /setup-api-tests (see the optional add-on section).
237
+ if compgen -G "$COLLECTIONS_DIR/*.json" >/dev/null 2>&1; then
238
+ run_collection_dir "API" "$COLLECTIONS_DIR" "api" "API" || true
601
239
  else
602
- # Single product mode: Run selected test suites
603
- if [ "$RUN_V3" = true ]; then
604
- run_collection_dir "V3 CRUD API" "$CRUD_COLLECTIONS_DIR" "crud" "V3_CRUD" || true
605
- echo ""
606
- run_collection_dir "V3 Files API" "$FILES_COLLECTIONS_DIR" "files" "V3_FILES" || true
240
+ shopt -s nullglob
241
+ for suite_dir in "$COLLECTIONS_DIR"/*/; do
242
+ suite=$(basename "$suite_dir")
243
+ run_collection_dir "$suite" "${suite_dir%/}" "$suite" "$suite" || true
607
244
  echo ""
608
- fi
609
-
610
- if [ "$RUN_V2" = true ]; then
611
- run_collection_dir "V2 API" "$V2_COLLECTIONS_DIR" "v2" "V2" || true
612
- echo ""
613
- fi
614
-
615
- if [ "$RUN_LEGACY" = true ]; then
616
- run_collection_dir "Legacy API" "$LEGACY_COLLECTIONS_DIR" "legacy" "LEGACY" || true
617
- echo ""
618
- fi
245
+ done
246
+ shopt -u nullglob
619
247
  fi
620
248
 
621
- # Summary
249
+ #==============================================================================
250
+ # REPORTING
251
+ #==============================================================================
252
+
622
253
  echo ""
623
254
  echo "========================================="
624
- if [ "$MULTI_PRODUCT" = true ]; then
625
- echo "Multi-Product Test Results"
626
- else
627
- echo "Staging Test Results"
628
- fi
255
+ echo "Staging Test Results"
629
256
  echo "========================================="
630
257
  echo ""
631
-
632
- if [ "$MULTI_PRODUCT" = true ]; then
633
- # Show per-product results
634
- echo "Product Results:"
635
- for product in $PRODUCTS; do
636
- status="${PRODUCT_STATUS[$product]}"
637
- crud_key="${product}_CRUD"
638
- files_key="${product}_FILES"
639
- crud_status="${COLLECTION_STATUS[$crud_key]}"
640
- files_status="${COLLECTION_STATUS[$files_key]}"
641
- crud_passed="${COLLECTION_PASSED[$crud_key]}"
642
- crud_failed="${COLLECTION_FAILED[$crud_key]}"
643
- files_passed="${COLLECTION_PASSED[$files_key]}"
644
- files_failed="${COLLECTION_FAILED[$files_key]}"
645
-
646
- # Use display name
647
- product_display="${PRODUCT_DISPLAY_NAMES[$product]}"
648
-
649
- if [ "$status" != "Not Run" ]; then
650
- echo " $product_display: $status"
651
- if [ "$crud_status" != "Not Run" ]; then
652
- echo " - CRUD API: $crud_status ($crud_passed passed, $crud_failed failed)"
653
- fi
654
- if [ "$files_status" != "Not Run" ]; then
655
- echo " - Files API: $files_status ($files_passed passed, $files_failed failed)"
656
- fi
657
- fi
658
- done
659
- else
660
- # Show per-collection results (original behavior)
661
- echo "Collection Results:"
662
- for collection_key in "V3_CRUD" "V3_FILES" "V2" "LEGACY"; do
663
- status="${COLLECTION_STATUS[$collection_key]}"
664
- passed="${COLLECTION_PASSED[$collection_key]}"
665
- failed="${COLLECTION_FAILED[$collection_key]}"
666
-
667
- if [ "$status" != "Not Run" ]; then
668
- case $collection_key in
669
- V3_CRUD)
670
- echo " V3 CRUD API: $status ($passed passed, $failed failed)"
671
- ;;
672
- V3_FILES)
673
- echo " V3 Files API: $status ($passed passed, $failed failed)"
674
- ;;
675
- V2)
676
- echo " V2 API: $status ($passed passed, $failed failed)"
677
- ;;
678
- LEGACY)
679
- echo " Legacy API: $status ($passed passed, $failed failed)"
680
- ;;
681
- esac
682
- fi
683
- done
684
- fi
685
-
258
+ echo "Collection Results:"
259
+ for collection_key in "${!COLLECTION_STATUS[@]}"; do
260
+ echo " $collection_key: ${COLLECTION_STATUS[$collection_key]} (${COLLECTION_PASSED[$collection_key]} passed, ${COLLECTION_FAILED[$collection_key]} failed)"
261
+ done
686
262
  echo ""
687
263
  echo "Overall Total: $TOTAL_PASSED passed, $TOTAL_FAILED failed"
688
264
  echo ""
689
265
  echo "Reports: $REPORT_DIR/"
690
266
  echo ""
691
267
 
692
- # Calculate passed/failed collections
693
268
  PASSED_COLLECTIONS=0
694
269
  FAILED_COLLECTIONS=0
695
- if [ "$MULTI_PRODUCT" = true ]; then
696
- # Count products as collections for multi-product mode
697
- for product in $PRODUCTS; do
698
- if [ "${PRODUCT_STATUS[$product]}" = "PASSED" ]; then
699
- PASSED_COLLECTIONS=$((PASSED_COLLECTIONS + 1))
700
- else
701
- FAILED_COLLECTIONS=$((FAILED_COLLECTIONS + 1))
702
- fi
703
- done
704
- else
705
- # Count individual collections
706
- for collection_key in "V3_CRUD" "V3_FILES" "V2" "LEGACY"; do
707
- status="${COLLECTION_STATUS[$collection_key]}"
708
- if [ "$status" != "Not Run" ]; then
709
- if [ "$status" = "✓ PASSED" ]; then
710
- PASSED_COLLECTIONS=$((PASSED_COLLECTIONS + 1))
711
- else
712
- FAILED_COLLECTIONS=$((FAILED_COLLECTIONS + 1))
713
- fi
714
- fi
715
- done
716
- fi
270
+ for collection_key in "${!COLLECTION_STATUS[@]}"; do
271
+ if [ "${COLLECTION_STATUS[$collection_key]}" = "✓ PASSED" ]; then
272
+ PASSED_COLLECTIONS=$((PASSED_COLLECTIONS + 1))
273
+ else
274
+ FAILED_COLLECTIONS=$((FAILED_COLLECTIONS + 1))
275
+ fi
276
+ done
717
277
 
718
- # Generate consolidated report
719
278
  if [ -f "$SCRIPT_DIR/../report-generators/generate-consolidated-report.sh" ]; then
720
279
  echo "========================================="
721
280
  echo "Generating Consolidated Report"
722
281
  echo "========================================="
723
282
  TEST_RESULT=0
724
- if [ $TOTAL_FAILED -gt 0 ]; then
725
- TEST_RESULT=1
726
- fi
283
+ [ $TOTAL_FAILED -gt 0 ] && TEST_RESULT=1
727
284
  "$SCRIPT_DIR/../report-generators/generate-consolidated-report.sh" "staging" "$TIMESTAMP" "$REPORT_DIR" "$PASSED_COLLECTIONS" "$FAILED_COLLECTIONS" "$TEST_RESULT" || true
728
285
  echo ""
729
286
  fi
730
287
 
731
- # Note: Reports are preserved across runs. Each script manages its own cleanup:
732
- # - mutation-report.sh: keeps only latest mutation report
733
- # - java-api-coverage-matrix.sh: keeps only latest coverage matrix
734
- # - Test reports: kept indefinitely (user can manually clean postman/reports/)
735
-
736
- if [ $TOTAL_FAILED -gt 0 ]; then
737
- echo "❌ Some tests failed"
738
- exit 1
739
- else
740
- echo "✅ All tests passed successfully!"
741
- fi
288
+ [ $TOTAL_FAILED -gt 0 ] && exit 1 || exit 0