diff --git a/README.md b/README.md
index 7e38f41..e7d0d35 100644
--- a/README.md
+++ b/README.md
@@ -101,7 +101,9 @@ You can find the latest published Docker images on Docker Hub:
* `TRIP_UPDATES_URL` - Trip Updates URL for GTFS-RT.
* `VEHICLE_POSITIONS_URL` - Vehicle Positions URL for GTFS-RT.
* `REFRESH_INTERVAL` - Refresh interval in seconds. Usually 10-30.
- * `AGENCY_ID` - Your GTFS-RT agency ID. Ostensibly the same as your GTFS agency ID.
+ * Specify one or the other:
+ * `AGENCY_ID_LIST` - Your GTFS-RT agency IDs. These should match the IDs in your agency.txt file. Format: abxoxo
+ * `AGENCY_ID` - Optional: Your GTFS-RT agency ID. Ostensibly the same as your GTFS agency ID.
* Authentication (Optional)
* Example: Specifying `FEED_API_KEY` = `X-API-KEY` and `FEED_API_VALUE` = `12345` will result in `X-API-KEY: 12345` being passed on every call to your GTFS-RT URLs.
* `FEED_API_KEY` - If your GTFS-RT API requires you to pass an authentication header, you can represent the key portion of it by specifying this value.
diff --git a/bin/validate.sh b/bin/validate.sh
index 22b36c4..8f9d99b 100755
--- a/bin/validate.sh
+++ b/bin/validate.sh
@@ -1,6 +1,9 @@
#!/bin/bash
-output=$(curl -s "http://localhost:8080/api/where/current-time.json?key=test" | jq '.data.entry.time')
+# Timeout for curl requests in seconds
+CURL_TIMEOUT=120
+
+output=$(curl -s --max-time $CURL_TIMEOUT "http://localhost:8080/api/where/current-time.json?key=test" | jq '.data.entry.time')
if [[ ! -z "$output" && "$output" =~ ^[0-9]+$ ]]; then
echo "current-time.json endpoint works."
@@ -10,7 +13,20 @@ else
fi
# Get the first agency from agencies-with-coverage
-agency_response=$(curl -s "http://localhost:8080/api/where/agencies-with-coverage.json?key=test")
+agency_response=$(curl -s --max-time $CURL_TIMEOUT "http://localhost:8080/api/where/agencies-with-coverage.json?key=test")
+
+# Debug: Show raw response if empty or small
+if [[ -z "$agency_response" || ${#agency_response} -lt 100 ]]; then
+ echo "Debug: Raw agency response: '$agency_response'"
+fi
+
+# Check if response is valid JSON
+if ! echo "$agency_response" | jq empty 2>/dev/null; then
+ echo "Error: Invalid JSON response from agencies-with-coverage endpoint"
+ echo "Response: $agency_response"
+ exit 1
+fi
+
agency_count=$(echo "$agency_response" | jq '.data.list | length')
if [[ "$agency_count" -gt 0 ]]; then
@@ -23,7 +39,7 @@ else
fi
# Get routes for the agency
-routes_response=$(curl -s "http://localhost:8080/api/where/routes-for-agency/${AGENCY_ID}.json?key=test")
+routes_response=$(curl -s --max-time $CURL_TIMEOUT "http://localhost:8080/api/where/routes-for-agency/${AGENCY_ID}.json?key=test")
route_count=$(echo "$routes_response" | jq '.data.list | length')
if [[ "$route_count" -gt 0 ]]; then
echo "routes-for-agency/${AGENCY_ID}.json endpoint works (found $route_count routes)."
@@ -35,7 +51,7 @@ else
fi
# Get stops for the route
-stops_response=$(curl -s "http://localhost:8080/api/where/stops-for-route/${ROUTE_ID}.json?key=test")
+stops_response=$(curl -s --max-time $CURL_TIMEOUT "http://localhost:8080/api/where/stops-for-route/${ROUTE_ID}.json?key=test")
route_id_check=$(echo "$stops_response" | jq -r '.data.entry.routeId')
if [[ ! -z "$route_id_check" && "$route_id_check" == "$ROUTE_ID" ]]; then
echo "stops-for-route/${ROUTE_ID}.json endpoint works."
@@ -47,7 +63,7 @@ else
fi
# Get stop details
-stop_response=$(curl -s "http://localhost:8080/api/where/stop/${STOP_ID}.json?key=test")
+stop_response=$(curl -s --max-time $CURL_TIMEOUT "http://localhost:8080/api/where/stop/${STOP_ID}.json?key=test")
stop_id_check=$(echo "$stop_response" | jq -r '.data.entry.id')
if [[ ! -z "$stop_id_check" && "$stop_id_check" == "$STOP_ID" ]]; then
echo "stop/${STOP_ID}.json endpoint works."
@@ -62,7 +78,7 @@ fi
# Test stops-for-location using coordinates from the stop
LOCATION_URL="http://localhost:8080/api/where/stops-for-location.json?lat=${STOP_LAT}&lon=${STOP_LON}&key=test"
-location_response=$(curl -s "$LOCATION_URL")
+location_response=$(curl -s --max-time $CURL_TIMEOUT "$LOCATION_URL")
out_of_range=$(echo "$location_response" | jq '.data.outOfRange')
stops_found=$(echo "$location_response" | jq '.data.list | length')
if [[ ! -z "$out_of_range" && "$out_of_range" == "false" && "$stops_found" -gt 0 ]]; then
@@ -75,7 +91,7 @@ else
fi
# Test arrivals-and-departures-for-stop endpoint
-arrivals_response=$(curl -s "http://localhost:8080/api/where/arrivals-and-departures-for-stop/${STOP_ID}.json?key=test")
+arrivals_response=$(curl -s --max-time $CURL_TIMEOUT "http://localhost:8080/api/where/arrivals-and-departures-for-stop/${STOP_ID}.json?key=test")
arrivals_stop_id=$(echo "$arrivals_response" | jq -r '.data.entry.stopId')
arrivals_count=$(echo "$arrivals_response" | jq '.data.entry.arrivalsAndDepartures | length // 0')
diff --git a/docker-compose.standalone.yml b/docker-compose.standalone.yml
index 7de2b9b..76918e2 100644
--- a/docker-compose.standalone.yml
+++ b/docker-compose.standalone.yml
@@ -43,8 +43,9 @@ services:
- JDBC_PASSWORD=oba_password
- TEST_API_KEY=test # For test only, remove in production
- TZ=America/Los_Angeles
+ - AGENCY_ID=unitrans
- GTFS_URL=https://unitrans.ucdavis.edu/media/gtfs/Unitrans_GTFS.zip
- - GTFS_TIDY_ARGS=v
+ - GTFS_TIDY_ARGS=OeD
ports:
# Access the webapp on your host machine at a path like
diff --git a/oba/bootstrap.sh b/oba/bootstrap.sh
index f7c9cbc..545ed66 100755
--- a/oba/bootstrap.sh
+++ b/oba/bootstrap.sh
@@ -46,8 +46,33 @@ else
HAS_API_KEY=""
fi
+# Handle AGENCY_ID_LIST properly - if it's a JSON array, use it directly, otherwise treat as empty
+if [ -n "$AGENCY_ID_LIST" ]; then
+ # Remove the outer quotes if they exist and use the array directly
+ AGENCY_ID_LIST_JSON="$AGENCY_ID_LIST"
+else
+ AGENCY_ID_LIST_JSON="[]"
+fi
+
+# Build the JSON string with proper handling of AGENCY_ID_LIST
+JSON_CONFIG=$(cat <
{{/if}}
-
+ {{#if AGENCY_ID_LIST.length}}
+
+
+ {{#each AGENCY_ID_LIST}}
+ {{ this }}
+ {{/each}}
+
+
+ {{else if AGENCY_ID}}
+
+ {{/if}}
{{#if HAS_API_KEY}}
diff --git a/oba/config/template_renderer/main_test.go b/oba/config/template_renderer/main_test.go
index a0c70e3..7d3f400 100644
--- a/oba/config/template_renderer/main_test.go
+++ b/oba/config/template_renderer/main_test.go
@@ -61,6 +61,61 @@ func TestRenderTemplate(t *testing.T) {
}
}
+func TestRenderTemplateWithArray(t *testing.T) {
+ // Create a temporary template file
+ tempFile, err := os.CreateTemp("", "test-template-*.hbs")
+ if err != nil {
+ t.Fatalf("Failed to create temp file: %v", err)
+ }
+ defer os.Remove(tempFile.Name()) // clean up
+
+ // Write test template content
+ templateContent := "Hello, {{name}}! Your favorite colors are {{#each colors}}{{this}} {{else}}unknown{{/each}}."
+ if _, err := tempFile.Write([]byte(templateContent)); err != nil {
+ t.Fatalf("Failed to write to temp file: %v", err)
+ }
+ if err := tempFile.Close(); err != nil {
+ t.Fatalf("Failed to close temp file: %v", err)
+ }
+
+ // Set up test cases
+ testCases := []struct {
+ name string
+ jsonData string
+ expected string
+ }{
+ {
+ name: "Basic rendering",
+ jsonData: `{"name": "Alice", "colors": ["blue", "green"]}`,
+ expected: "Hello, Alice! Your favorite colors are blue green .",
+ },
+ {
+ name: "only one item rendering",
+ jsonData: `{"name": "Alice", "colors": ["green"]}`,
+ expected: "Hello, Alice! Your favorite colors are green .",
+ },
+ {
+ name: "only one item rendering",
+ jsonData: `{"name": "Alice", "colors": []}`,
+ expected: "Hello, Alice! Your favorite colors are unknown.",
+ },
+ }
+
+ // Run test cases
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ result, err := renderTemplate(tempFile.Name(), tc.jsonData)
+ if err != nil {
+ t.Fatalf("renderTemplate returned an error: %v", err)
+ }
+
+ if !strings.Contains(result, tc.expected) {
+ t.Errorf("Expected output to contain %q, but got %q", tc.expected, result)
+ }
+ })
+ }
+}
+
func TestRenderTemplateErrors(t *testing.T) {
// Test with non-existent file
_, err := renderTemplate("non-existent-file.hbs", "{}")