test-neo4j-integration.sh raw
1 #!/bin/bash
2 # Neo4j Integration Test Runner
3 #
4 # This script runs the Neo4j integration tests by:
5 # 1. Checking if Docker/Docker Compose are available
6 # 2. Starting a Neo4j container
7 # 3. Running the integration tests
8 # 4. Stopping the container
9 #
10 # Usage:
11 # ./scripts/test-neo4j-integration.sh
12 #
13 # Environment variables:
14 # SKIP_DOCKER_INSTALL=1 - Skip Docker installation check
15 # KEEP_CONTAINER=1 - Don't stop container after tests
16 # NEO4J_TEST_REQUIRED=1 - Fail if Docker/Neo4j not available (for local testing)
17 #
18 # Exit codes:
19 # 0 - Tests passed OR Docker/Neo4j not available (soft fail for CI)
20 # 1 - Tests failed (only when Neo4j is available)
21 # 2 - Tests required but Docker/Neo4j not available (when NEO4J_TEST_REQUIRED=1)
22
23 set -e
24
25 SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
26 PROJECT_ROOT="$(cd "$SCRIPT_DIR/.." && pwd)"
27 COMPOSE_FILE="$PROJECT_ROOT/pkg/neo4j/docker-compose.yaml"
28 CONTAINER_NAME="neo4j-test"
29
30 # Colors for output
31 RED='\033[0;31m'
32 GREEN='\033[0;32m'
33 YELLOW='\033[1;33m'
34 BLUE='\033[0;34m'
35 NC='\033[0m' # No Color
36
37 log_info() {
38 echo -e "${GREEN}[INFO]${NC} $1"
39 }
40
41 log_warn() {
42 echo -e "${YELLOW}[WARN]${NC} $1"
43 }
44
45 log_error() {
46 echo -e "${RED}[ERROR]${NC} $1"
47 }
48
49 log_skip() {
50 echo -e "${BLUE}[SKIP]${NC} $1"
51 }
52
53 # Soft fail - exit 0 for CI compatibility unless NEO4J_TEST_REQUIRED is set
54 soft_fail() {
55 local message="$1"
56 if [ "$NEO4J_TEST_REQUIRED" = "1" ]; then
57 log_error "$message"
58 log_error "NEO4J_TEST_REQUIRED=1 is set, failing"
59 exit 2
60 else
61 log_skip "$message"
62 log_skip "Neo4j integration tests skipped (set NEO4J_TEST_REQUIRED=1 to require)"
63 exit 0
64 fi
65 }
66
67 # Check if Docker is installed and running
68 check_docker() {
69 if ! command -v docker &> /dev/null; then
70 soft_fail "Docker is not installed"
71 return 1
72 fi
73
74 if ! docker info &> /dev/null 2>&1; then
75 soft_fail "Docker daemon is not running or permission denied"
76 return 1
77 fi
78
79 log_info "Docker is available"
80 return 0
81 }
82
83 # Check if Docker Compose is installed
84 check_docker_compose() {
85 # Try docker compose (v2) first, then docker-compose (v1)
86 if docker compose version &> /dev/null 2>&1; then
87 COMPOSE_CMD="docker compose"
88 log_info "Using Docker Compose v2"
89 return 0
90 elif command -v docker-compose &> /dev/null; then
91 COMPOSE_CMD="docker-compose"
92 log_info "Using Docker Compose v1"
93 return 0
94 else
95 soft_fail "Docker Compose is not installed"
96 return 1
97 fi
98 }
99
100 # Start Neo4j container
101 start_neo4j() {
102 log_info "Starting Neo4j container..."
103
104 cd "$PROJECT_ROOT"
105
106 # Try to start container, soft fail if it doesn't work
107 if ! $COMPOSE_CMD -f "$COMPOSE_FILE" up -d 2>&1; then
108 soft_fail "Failed to start Neo4j container"
109 return 1
110 fi
111
112 log_info "Waiting for Neo4j to become healthy..."
113
114 # Wait for container to be healthy (up to 2 minutes)
115 local timeout=120
116 local elapsed=0
117
118 while [ $elapsed -lt $timeout ]; do
119 local health=$(docker inspect --format='{{.State.Health.Status}}' "$CONTAINER_NAME" 2>/dev/null || echo "not_found")
120
121 if [ "$health" = "healthy" ]; then
122 log_info "Neo4j is healthy and ready"
123 return 0
124 elif [ "$health" = "not_found" ]; then
125 log_warn "Container $CONTAINER_NAME not found, retrying..."
126 fi
127
128 echo -n "."
129 sleep 2
130 elapsed=$((elapsed + 2))
131 done
132
133 echo ""
134 log_warn "Neo4j failed to become healthy within $timeout seconds"
135 log_info "Container logs:"
136 docker logs "$CONTAINER_NAME" --tail 20 2>/dev/null || true
137
138 # Clean up failed container
139 $COMPOSE_CMD -f "$COMPOSE_FILE" down -v 2>/dev/null || true
140
141 soft_fail "Neo4j container failed to start properly"
142 return 1
143 }
144
145 # Stop Neo4j container
146 stop_neo4j() {
147 if [ "$KEEP_CONTAINER" = "1" ]; then
148 log_info "KEEP_CONTAINER=1, leaving Neo4j running"
149 return 0
150 fi
151
152 log_info "Stopping Neo4j container..."
153 cd "$PROJECT_ROOT"
154 $COMPOSE_CMD -f "$COMPOSE_FILE" down -v 2>/dev/null || true
155 }
156
157 # Run integration tests
158 run_tests() {
159 log_info "Running Neo4j integration tests..."
160
161 cd "$PROJECT_ROOT"
162
163 # Set environment variables for tests
164 # Note: Tests use ORLY_NEO4J_* prefix (consistent with app config)
165 export ORLY_NEO4J_URI="bolt://localhost:7687"
166 export ORLY_NEO4J_USER="neo4j"
167 export ORLY_NEO4J_PASSWORD="testpassword"
168 # Also set NEO4J_TEST_URI for testmain_test.go compatibility
169 export NEO4J_TEST_URI="bolt://localhost:7687"
170
171 # Run tests with integration tag
172 if go test -tags=integration ./pkg/neo4j/... -v -timeout 5m; then
173 log_info "All integration tests passed!"
174 return 0
175 else
176 log_error "Some integration tests failed"
177 return 1
178 fi
179 }
180
181 # Main execution
182 main() {
183 log_info "Neo4j Integration Test Runner"
184 log_info "=============================="
185
186 if [ "$NEO4J_TEST_REQUIRED" = "1" ]; then
187 log_info "NEO4J_TEST_REQUIRED=1 - tests will fail if Neo4j unavailable"
188 else
189 log_info "NEO4J_TEST_REQUIRED not set - tests will skip if Neo4j unavailable"
190 fi
191
192 # Check prerequisites (these will soft_fail if not available)
193 check_docker || exit $?
194 check_docker_compose || exit $?
195
196 # Check if compose file exists
197 if [ ! -f "$COMPOSE_FILE" ]; then
198 soft_fail "Docker Compose file not found: $COMPOSE_FILE"
199 fi
200
201 # Track if we need to stop the container
202 local need_cleanup=0
203
204 # Check if container is already running
205 if docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^${CONTAINER_NAME}$"; then
206 log_info "Neo4j container is already running"
207 else
208 start_neo4j || exit $?
209 need_cleanup=1
210 fi
211
212 # Run tests
213 local test_result=0
214 run_tests || test_result=1
215
216 # Cleanup
217 if [ $need_cleanup -eq 1 ]; then
218 stop_neo4j
219 fi
220
221 if [ $test_result -eq 0 ]; then
222 log_info "Integration tests completed successfully"
223 else
224 log_error "Integration tests failed"
225 fi
226
227 exit $test_result
228 }
229
230 # Handle cleanup on script exit
231 cleanup() {
232 if [ "$KEEP_CONTAINER" != "1" ] && docker ps --format '{{.Names}}' 2>/dev/null | grep -q "^${CONTAINER_NAME}$"; then
233 log_warn "Cleaning up after interrupt..."
234 stop_neo4j
235 fi
236 }
237
238 trap cleanup EXIT INT TERM
239
240 main "$@"
241