-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathMakefile
More file actions
664 lines (567 loc) · 28.8 KB
/
Copy pathMakefile
File metadata and controls
664 lines (567 loc) · 28.8 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
# Excalibase GraphQL Makefile
# Provides e2e testing and development commands
# Configuration
COMPOSE_PROJECT = excalibase-app
COMPOSE_FILE = docker-compose.yml
OBSERVABILITY_FILE = docker-compose.observability.yml
OBSERVABILITY_PROJECT = excalibase-obs
APP_PORT = 10000
DB_PORT = 5432
API_URL = http://localhost:$(APP_PORT)/graphql
# Colors for output
BLUE = \033[0;34m
GREEN = \033[0;32m
YELLOW = \033[1;33m
RED = \033[0;31m
NC = \033[0m # No Color
# Default target
.DEFAULT_GOAL := help
# Help target
.PHONY: help
help: ## Show this help message
@echo "$(BLUE)Excalibase GraphQL - Available Commands$(NC)"
@echo ""
@awk 'BEGIN {FS = ":.*?## "} /^[a-zA-Z_-]+:.*?## / {printf " $(GREEN)%-15s$(NC) %s\n", $$1, $$2}' $(MAKEFILE_LIST)
@echo ""
@echo "$(YELLOW)Examples:$(NC)"
@echo " make e2e # Complete Postgres e2e test (JVM)"
@echo " make postgres-e2e-native # Complete Postgres e2e test (native)"
@echo " make mysql-e2e # Complete MySQL e2e test (JVM)"
@echo " make dev # Build then start services and keep running"
@echo " make up # Pull and start service from docker hub "
@echo " make test-only # Run tests against running services"
@echo " make clean # Stop services and cleanup"
@echo ""
@echo "$(YELLOW)Enterprise Benchmarking:$(NC)"
@echo " make benchmark # Complete enterprise benchmark (16.7M+ records)"
@echo " make benchmark-dev # Start enterprise benchmark environment"
@echo " make benchmark-test # Run enterprise benchmark tests only"
@echo ""
@echo "$(YELLOW)K6 Load Testing:$(NC)"
@echo " make benchmark-k6-spring # Run K6 benchmark against Spring Boot"
@echo " ./scripts/run-k6-benchmark.sh quick # Quick 30s test"
@echo " ./scripts/run-k6-benchmark.sh full # Full benchmark (~15min)"
@echo ""
@echo "$(YELLOW)Enterprise Debugging:$(NC)"
@echo " make benchmark-logs # Show service logs"
@echo " make benchmark-db-shell # Connect to database"
@echo " make benchmark-db-stats # Show database statistics"
@echo ""
@echo "$(YELLOW)CI/CD Integration:$(NC)"
@echo " make ci # Run complete CI pipeline"
@echo " make ci-benchmark # Run enterprise benchmarks for CI"
# Main targets
.PHONY: e2e
e2e: down build-image up test clean ## Complete e2e test suite (cleanup, build image, test, cleanup)
@echo "$(GREEN)🎉 E2E testing completed successfully!$(NC)"
.PHONY: dev
dev: build-image up ## Start services for development (no cleanup)
@echo ""
@echo "$(GREEN)🚀 Development environment ready!$(NC)"
@echo ""
@echo "$(BLUE)GraphQL API:$(NC) $(API_URL)"
@echo "$(BLUE)PostgreSQL:$(NC) localhost:$(DB_PORT)"
@echo ""
@echo "$(YELLOW)To run tests:$(NC) make test-only"
@echo "$(YELLOW)To cleanup:$(NC) make clean"
@echo ""
.PHONY: test-all
test-all: ## Run all tests: unit + Postgres/MySQL/Multi-tenant E2E (JVM)
@echo "$(BLUE)🧪 Running unit and integration tests...$(NC)"
@mvn test -q || (echo "$(RED)❌ Unit/integration tests failed$(NC)" && exit 1)
@echo "$(GREEN)✓ Unit/integration tests passed$(NC)"
@$(MAKE) --no-print-directory e2e
@$(MAKE) --no-print-directory mysql-e2e
@$(MAKE) --no-print-directory multi-tenant-e2e
@echo "$(GREEN)🎉 All tests passed!$(NC)"
.PHONY: ci
ci: build-image up test clean ## CI/CD pipeline
.PHONY: ci-benchmark
ci-benchmark: benchmark-build benchmark-up benchmark-test-only ## Enterprise benchmark for CI (without cleanup)
@echo "$(GREEN)🏢 Enterprise CI benchmark completed!$(NC)"
# MySQL targets
MYSQL_COMPOSE_FILE = docker-compose.mysql.yml
MYSQL_COMPOSE_PROJECT = excalibase-mysql-app
MYSQL_API_PORT = 10001
# Native e2e targets
NATIVE_COMPOSE_FILE = docker-compose.native.yml
NATIVE_COMPOSE_PROJECT = excalibase-native-app
.PHONY: mysql-e2e
mysql-e2e: down-mysql build-image mysql-up mysql-test mysql-clean ## Complete MySQL e2e test suite (JVM)
@echo "$(GREEN)🎉 MySQL E2E testing completed successfully!$(NC)"
.PHONY: postgres-e2e-native
postgres-e2e-native: down-native build-native-image up-native test-only-native clean-native ## Complete Postgres e2e test suite (native image)
@echo "$(GREEN)🎉 Postgres Native E2E testing completed successfully!$(NC)"
.PHONY: mysql-dev
mysql-dev: build-image mysql-up ## Start MySQL services for development
@echo ""
@echo "$(GREEN)🚀 MySQL development environment ready!$(NC)"
@echo "$(BLUE)GraphQL API:$(NC) http://localhost:$(MYSQL_API_PORT)/graphql"
@echo "$(BLUE)MySQL:$(NC) localhost:3306"
@echo ""
.PHONY: mysql-up
mysql-up: ## Start MySQL Docker services
@echo "$(BLUE)🚀 Starting MySQL services...$(NC)"
@docker compose -f $(MYSQL_COMPOSE_FILE) -p $(MYSQL_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f $(MYSQL_COMPOSE_FILE) -p $(MYSQL_COMPOSE_PROJECT) up -d 2>&1 || true
@$(MAKE) --no-print-directory mysql-wait-ready
.PHONY: mysql-wait-ready
mysql-wait-ready: ## Wait for MySQL GraphQL API to be ready
@echo "$(BLUE)⏳ Waiting for MySQL services...$(NC)"
@for i in $$(seq 1 40); do \
if curl -s -X POST http://localhost:$(MYSQL_API_PORT)/graphql -H 'Content-Type: application/json' -d '{"query":"{ __typename }"}' 2>/dev/null | grep -q "data\|error"; then \
echo "$(GREEN)✓ MySQL GraphQL API ready$(NC)"; \
break; \
fi; \
if [ $$i -eq 40 ]; then \
echo "$(RED)❌ MySQL application failed to start$(NC)"; \
exit 1; \
fi; \
printf "."; \
sleep 3; \
done
.PHONY: mysql-down
down-mysql: ## Stop MySQL Docker services
@echo "$(BLUE)🛑 Stopping MySQL services...$(NC)"
@docker compose -f $(MYSQL_COMPOSE_FILE) -p $(MYSQL_COMPOSE_PROJECT) down > /dev/null 2>&1 || true
@echo "$(GREEN)✓ MySQL services stopped$(NC)"
.PHONY: mysql-clean
mysql-clean: ## Stop MySQL services and cleanup volumes
@docker compose -f $(MYSQL_COMPOSE_FILE) -p $(MYSQL_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
.PHONY: mysql-test
mysql-test: ## Run MySQL e2e tests (requires services running)
@echo "$(BLUE)🧪 Running MySQL E2E tests...$(NC)"
@cd e2e && npm install --silent && npm run test:mysql || (echo "$(RED)❌ MySQL tests failed$(NC)" && exit 1)
@echo "$(BLUE)🧪 Running MySQL CDC subscription tests...$(NC)"
@cd e2e && npm run test:subscription:mysql || (echo "$(RED)❌ MySQL subscription tests failed$(NC)" && exit 1)
# Multi-tenant targets
MT_COMPOSE_FILE = e2e/multi-tenant/docker-compose.multi-tenant.yml
MT_COMPOSE_PROJECT = excalibase-multi-tenant
MT_API_PORT = 10003
.PHONY: multi-tenant-e2e
multi-tenant-e2e: down-multi-tenant build-image multi-tenant-generate-keys multi-tenant-up multi-tenant-test multi-tenant-clean ## Complete multi-tenant e2e test suite
@echo "$(GREEN)🎉 Multi-tenant E2E testing completed successfully!$(NC)"
.PHONY: multi-tenant-generate-keys
multi-tenant-generate-keys: ## Generate test EC keypair for multi-tenant WireMock
@e2e/multi-tenant/generate-keys.sh
.PHONY: multi-tenant-up
multi-tenant-up: ## Start multi-tenant Docker services
@echo "$(BLUE)🚀 Starting multi-tenant services...$(NC)"
@docker compose -f $(MT_COMPOSE_FILE) -p $(MT_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f $(MT_COMPOSE_FILE) -p $(MT_COMPOSE_PROJECT) up -d 2>&1 || true
@echo "$(GREEN)✓ Multi-tenant services started$(NC)"
@$(MAKE) --no-print-directory multi-tenant-wait-ready
.PHONY: down-multi-tenant
down-multi-tenant: ## Stop multi-tenant Docker services
@echo "$(BLUE)🛑 Stopping multi-tenant services...$(NC)"
@docker compose -f $(MT_COMPOSE_FILE) -p $(MT_COMPOSE_PROJECT) down > /dev/null 2>&1 || true
@echo "$(GREEN)✓ Multi-tenant services stopped$(NC)"
.PHONY: multi-tenant-clean
multi-tenant-clean: ## Stop multi-tenant services and cleanup volumes
@docker compose -f $(MT_COMPOSE_FILE) -p $(MT_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
.PHONY: multi-tenant-test
multi-tenant-test: ## Run multi-tenant e2e tests
@echo "$(BLUE)🧪 Running multi-tenant E2E tests...$(NC)"
@cd e2e && npm install --silent && npm run test:multi-tenant || (echo "$(RED)❌ Multi-tenant tests failed$(NC)" && exit 1)
.PHONY: multi-tenant-wait-ready
multi-tenant-wait-ready:
@echo "$(BLUE)⏳ Waiting for multi-tenant services...$(NC)"
@for i in $$(seq 1 30); do \
if curl -s -X POST http://localhost:$(MT_API_PORT)/graphql -H 'Content-Type: application/json' -d '{"query":"{ __typename }"}' 2>/dev/null | grep -q "data\|error"; then \
echo "$(GREEN)✓ Multi-tenant GraphQL API ready$(NC)"; \
break; \
fi; \
if [ $$i -eq 30 ]; then \
echo "$(RED)❌ Multi-tenant application failed to start$(NC)"; \
exit 1; \
fi; \
printf "."; \
sleep 3; \
done
SC_COMPOSE_FILE = e2e/study-cases/docker-compose.study-cases.yml
SC_COMPOSE_PROJECT = excalibase-study-cases
SC_API_PORT = 10004
SC_AUTH_PORT = 24004
.PHONY: study-cases-e2e
study-cases-e2e: down-study-cases build-image study-cases-generate-keys study-cases-up study-cases-test study-cases-clean ## Complete study-cases e2e test suite
.PHONY: study-cases-generate-keys
study-cases-generate-keys: ## Generate test EC keypair for study-cases WireMock
@e2e/study-cases/generate-keys.sh
.PHONY: study-cases-up
study-cases-up: ## Start study-cases Docker services
@echo "$(BLUE)🚀 Starting study-cases services...$(NC)"
@docker compose -f $(SC_COMPOSE_FILE) -p $(SC_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f $(SC_COMPOSE_FILE) -p $(SC_COMPOSE_PROJECT) up -d 2>&1 || true
@$(MAKE) --no-print-directory study-cases-wait-ready
.PHONY: down-study-cases
down-study-cases: ## Stop study-cases Docker services
@echo "$(BLUE)🛑 Stopping study-cases services...$(NC)"
@docker compose -f $(SC_COMPOSE_FILE) -p $(SC_COMPOSE_PROJECT) down > /dev/null 2>&1 || true
.PHONY: study-cases-clean
study-cases-clean: ## Stop study-cases services and cleanup volumes
@docker compose -f $(SC_COMPOSE_FILE) -p $(SC_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
.PHONY: study-cases-test
study-cases-test: ## Run study-cases e2e tests
@echo "$(BLUE)🧪 Running study-cases E2E tests...$(NC)"
@cd e2e && SC_GRAPHQL_URL=http://localhost:$(SC_API_PORT)/graphql SC_AUTH_URL=http://localhost:$(SC_AUTH_PORT)/auth npm install --silent && \
SC_GRAPHQL_URL=http://localhost:$(SC_API_PORT)/graphql SC_AUTH_URL=http://localhost:$(SC_AUTH_PORT)/auth npm run test:study-cases || \
(echo "$(RED)❌ Study-cases tests failed$(NC)" && exit 1)
.PHONY: study-cases-wait-ready
study-cases-wait-ready:
@echo "$(BLUE)⏳ Waiting for study-cases services...$(NC)"
@for i in $$(seq 1 40); do \
if curl -s -X POST http://localhost:$(SC_API_PORT)/graphql -H 'Content-Type: application/json' -d '{"query":"{ __typename }"}' 2>/dev/null | grep -q "data\|errors\|Unauthorized\|401"; then \
echo "$(GREEN)✓ Study-cases GraphQL API ready$(NC)"; \
break; \
fi; \
if [ $$i -eq 40 ]; then \
echo "$(RED)❌ Study-cases application failed to start$(NC)"; \
exit 1; \
fi; \
printf "."; \
sleep 5; \
done
# CDC subscription test targets
.PHONY: subscription-test
subscription-test: ## Run Postgres CDC subscription e2e tests (requires make up)
@echo "$(BLUE)🧪 Running Postgres subscription tests...$(NC)"
@cd e2e && npm install --silent && npm run test:subscription:postgres || (echo "$(RED)❌ Postgres subscription tests failed$(NC)" && exit 1)
.PHONY: mysql-subscription-test
mysql-subscription-test: ## Run MySQL CDC subscription e2e tests (requires mysql-up)
@echo "$(BLUE)🧪 Running MySQL subscription tests...$(NC)"
@cd e2e && npm install --silent && npm run test:subscription:mysql || (echo "$(RED)❌ MySQL subscription tests failed$(NC)" && exit 1)
# Benchmark targets (postgres and mysql, jvm and native)
.PHONY: benchmark-postgres-jvm
benchmark-postgres-jvm: ## Run Postgres JVM benchmark (quick)
@./scripts/benchmark-postgres.sh jvm quick
.PHONY: benchmark-mysql-jvm
benchmark-mysql-jvm: ## Run MySQL JVM benchmark (quick)
@./scripts/benchmark-mysql.sh jvm quick
# Build targets
.PHONY: build
build: ## Build the application with Maven
@echo "$(BLUE)🔨 Building application...$(NC)"
@mvn clean package -DskipTests -q
@echo "$(GREEN)✓ Build completed$(NC)"
GRAALVM_HOME ?= $(HOME)/.sdkman/candidates/java/25.0.2-graalce
.PHONY: build-native
build-native: ## Build native image (requires GraalVM JDK 25, ~10 min)
@echo "$(BLUE)🔨 Building native image...$(NC)"
@JAVA_HOME=$(GRAALVM_HOME) PATH=$(GRAALVM_HOME)/bin:$(PATH) mvn -pl modules/excalibase-graphql-api -am -Pnative package -DskipTests -q
@echo "$(GREEN)✓ Native image built: modules/excalibase-graphql-api/target/excalibase-graphql-api$(NC)"
.PHONY: build-native-image
build-native-image: build-native ## Build native Docker image
@echo "$(BLUE)🐳 Building native Docker image...$(NC)"
@docker build --no-cache -f Dockerfile.native -t excalibase/excalibase-graphql:native .
@echo "$(GREEN)✓ Native Docker image built$(NC)"
.PHONY: build-image
build-image: build ## Build Docker image locally for e2e testing
@echo "$(BLUE)🐳 Building Docker image...$(NC)"
@docker build -t excalibase/excalibase-graphql .
@echo "$(GREEN)✓ Docker image built$(NC)"
.PHONY: watcher-go-build
watcher-go-build: ## Build excalibase-watcher-go:local image from sibling repo
@echo "$(BLUE)🐳 Building excalibase-watcher-go:local...$(NC)"
@docker build -t excalibase/excalibase-watcher-go:local $(HOME)/Documents/duk/excalibase-watcher-go
@echo "$(GREEN)✓ watcher-go image built$(NC)"
.PHONY: build-skip
build-skip: ## Skip Maven build (for rapid iteration)
@echo "$(YELLOW)⚠️ Skipping Maven build$(NC)"
# Key generation for WireMock mock-vault
.PHONY: generate-keys
generate-keys: ## Generate test EC keypair and WireMock stubs
@e2e/generate-keys.sh
# Service management
.PHONY: up
up: generate-keys ## Start Docker services (app + observability)
@echo "$(BLUE)🚀 Starting services...$(NC)"
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) up -d 2>&1 || true
@echo "$(GREEN)✓ App services started$(NC)"
@echo "$(BLUE)📊 Starting observability stack...$(NC)"
@docker compose -f $(OBSERVABILITY_FILE) -p $(OBSERVABILITY_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f $(OBSERVABILITY_FILE) -p $(OBSERVABILITY_PROJECT) up -d 2>&1 || true
@echo "$(GREEN)✓ Observability services started$(NC)"
@$(MAKE) --no-print-directory wait-ready
.PHONY: down
down: ## Stop Docker services (app + observability)
@echo "$(BLUE)🛑 Stopping services...$(NC)"
@docker compose -f $(OBSERVABILITY_FILE) -p $(OBSERVABILITY_PROJECT) down > /dev/null 2>&1 || true
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) down > /dev/null 2>&1 || true
@echo "$(GREEN)✓ Services stopped$(NC)"
.PHONY: clean
clean: ## Stop services and cleanup volumes (app + observability)
@echo "$(BLUE)🧹 Cleaning up...$(NC)"
@docker compose -f $(OBSERVABILITY_FILE) -p $(OBSERVABILITY_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@echo "$(GREEN)✓ Cleanup completed$(NC)"
.PHONY: logs
logs: ## Show service logs
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) logs -f
.PHONY: logs-app
logs-app: ## Show application logs only
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) logs -f app
.PHONY: logs-db
logs-db: ## Show database logs only
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) logs -f postgres
.PHONY: status
status: ## Show service status
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) ps
# Testing targets
.PHONY: test
test: up test-only ## Start services and run tests
@echo "$(GREEN)✓ Tests completed$(NC)"
.PHONY: test-only
test-only: ## Run e2e tests (requires services to be running)
@echo "$(BLUE)🧪 Running E2E tests...$(NC)"
@$(MAKE) --no-print-directory run-tests
.PHONY: test-quick
test-quick: build-skip up test-only ## Quick test (skip build)
@echo "$(GREEN)✓ Quick tests completed$(NC)"
# Internal targets
.PHONY: wait-ready
wait-ready: ## Wait for services to be ready
@echo "$(BLUE)⏳ Waiting for services...$(NC)"
@for i in $$(seq 1 30); do \
if docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) exec -T postgres pg_isready -U hana001 -d hana > /dev/null 2>&1; then \
echo "$(GREEN)✓ PostgreSQL ready$(NC)"; \
break; \
fi; \
if [ $$i -eq 30 ]; then \
echo "$(RED)❌ PostgreSQL failed to start$(NC)"; \
exit 1; \
fi; \
printf "."; \
sleep 2; \
done
@echo "$(BLUE)🔄 Waiting for application...$(NC)"
@for i in $$(seq 1 30); do \
if curl -s -X POST http://localhost:$(APP_PORT)/graphql -H 'Content-Type: application/json' -d '{"query":"{ __typename }"}' 2>/dev/null | grep -q "data"; then \
echo "$(GREEN)✓ GraphQL API ready$(NC)"; \
break; \
fi; \
if [ $$i -eq 30 ]; then \
echo "$(RED)❌ Application failed to start$(NC)"; \
exit 1; \
fi; \
printf "."; \
sleep 2; \
done
@echo "$(GREEN)✓ All services ready$(NC)"
.PHONY: up-native
up-native: generate-keys ## Start Postgres Docker services using native image
@echo "$(BLUE)🚀 Starting native services...$(NC)"
@docker compose -f $(NATIVE_COMPOSE_FILE) -p $(NATIVE_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f $(NATIVE_COMPOSE_FILE) -p $(NATIVE_COMPOSE_PROJECT) up -d 2>&1 || true
@echo "$(GREEN)✓ Native services started$(NC)"
@$(MAKE) --no-print-directory wait-ready-native
.PHONY: down-native
down-native: ## Stop native Postgres Docker services
@echo "$(BLUE)🛑 Stopping native services...$(NC)"
@docker compose -f $(NATIVE_COMPOSE_FILE) -p $(NATIVE_COMPOSE_PROJECT) down > /dev/null 2>&1 || true
@echo "$(GREEN)✓ Native services stopped$(NC)"
.PHONY: clean-native
clean-native: ## Stop native Postgres services and cleanup volumes
@docker compose -f $(NATIVE_COMPOSE_FILE) -p $(NATIVE_COMPOSE_PROJECT) down -v --remove-orphans > /dev/null 2>&1 || true
.PHONY: wait-ready-native
wait-ready-native: ## Wait for native services to be ready
@echo "$(BLUE)⏳ Waiting for native services...$(NC)"
@for i in $$(seq 1 30); do \
if docker compose -f $(NATIVE_COMPOSE_FILE) -p $(NATIVE_COMPOSE_PROJECT) exec -T postgres pg_isready -U hana001 -d hana > /dev/null 2>&1; then \
echo "$(GREEN)✓ PostgreSQL ready$(NC)"; \
break; \
fi; \
if [ $$i -eq 30 ]; then \
echo "$(RED)❌ PostgreSQL failed to start$(NC)"; \
exit 1; \
fi; \
printf "."; \
sleep 2; \
done
@echo "$(BLUE)🔄 Waiting for native application...$(NC)"
@for i in $$(seq 1 30); do \
if curl -s -X POST http://localhost:$(APP_PORT)/graphql -H 'Content-Type: application/json' -d '{"query":"{ __typename }"}' 2>/dev/null | grep -q "data"; then \
echo "$(GREEN)✓ GraphQL API ready$(NC)"; \
break; \
fi; \
if [ $$i -eq 30 ]; then \
echo "$(RED)❌ Native application failed to start$(NC)"; \
exit 1; \
fi; \
printf "."; \
sleep 2; \
done
@echo "$(GREEN)✓ All native services ready$(NC)"
.PHONY: test-only-native
test-only-native: ## Run e2e tests against native containers
@echo "$(BLUE)🧪 Running Native E2E tests...$(NC)"
@$(MAKE) --no-print-directory run-tests-native
.PHONY: run-tests-native
run-tests-native: ## Execute test suite against native containers
@cd e2e && npm install --silent && npm run test:postgres || (echo "$(RED)❌ Postgres tests failed$(NC)" && exit 1)
@echo "$(BLUE)🧪 Running CDC subscription tests (native)...$(NC)"
@cd e2e && PG_CONTAINER=excalibase-postgres-native npm run test:subscription:postgres || (echo "$(RED)❌ Subscription tests failed$(NC)" && exit 1)
.PHONY: run-tests
run-tests: ## Execute the actual test suite (queries/mutations + CDC subscriptions)
@cd e2e && npm install --silent && npm run test:postgres || (echo "$(RED)❌ Postgres tests failed$(NC)" && exit 1)
@echo "$(BLUE)🧪 Running CDC subscription tests...$(NC)"
@cd e2e && npm run test:subscription:postgres || (echo "$(RED)❌ Subscription tests failed$(NC)" && exit 1)
# Database operations (unified schema with demo + test data)
.PHONY: db-shell
db-shell: ## Connect to PostgreSQL shell
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) exec postgres psql -U hana001 -d hana
.PHONY: db-reset
db-reset: ## Reset database (recreate with fresh data)
@echo "$(BLUE)🔄 Resetting database...$(NC)"
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) down -v > /dev/null 2>&1 || true
@docker compose -f $(COMPOSE_FILE) -p $(COMPOSE_PROJECT) up -d postgres > /dev/null 2>&1
@$(MAKE) --no-print-directory wait-ready
@echo "$(GREEN)✓ Database reset completed$(NC)"
# Development workflow targets
.PHONY: restart
restart: down up ## Restart services
@echo "$(GREEN)✓ Services restarted$(NC)"
.PHONY: rebuild
rebuild: clean build up ## Full rebuild and restart
@echo "$(GREEN)✓ Full rebuild completed$(NC)"
# Enterprise benchmark targets
.PHONY: benchmark
benchmark: benchmark-build benchmark-up benchmark-test benchmark-clean ## Complete enterprise benchmark test suite
@echo "$(GREEN)🎉 Enterprise benchmark testing completed successfully!$(NC)"
.PHONY: benchmark-dev
benchmark-dev: benchmark-build benchmark-up ## Start enterprise benchmark services for development
@echo ""
@echo "$(GREEN)🚀 Enterprise benchmark environment ready!$(NC)"
@echo ""
@echo "$(BLUE)GraphQL API:$(NC) http://localhost:10002/graphql"
@echo "$(BLUE)PostgreSQL:$(NC) localhost:5434"
@echo ""
@echo "$(YELLOW)To run benchmark tests:$(NC) make benchmark-test-only"
@echo "$(YELLOW)To cleanup:$(NC) make benchmark-clean"
@echo ""
.PHONY: benchmark-k6-spring
benchmark-k6-spring: ## Run K6 benchmark against Spring Boot
@echo "$(BLUE)📊 Running K6 benchmark for Spring Boot...$(NC)"
@./scripts/run-k6-benchmark.sh full
.PHONY: benchmark-build
benchmark-build: ## Build application for enterprise benchmarking
@echo "$(BLUE)🔨 Building application for enterprise benchmarking...$(NC)"
@mvn clean package -DskipTests -q
@echo "$(GREEN)✓ Enterprise benchmark build completed$(NC)"
.PHONY: benchmark-up
benchmark-up: ## Start enterprise benchmark Docker services
@echo "$(BLUE)🚀 Starting enterprise benchmark services...$(NC)"
@docker compose -f scripts/docker-compose.benchmark.yml -p excalibase-benchmark down -v --remove-orphans > /dev/null 2>&1 || true
@docker compose -f scripts/docker-compose.benchmark.yml -p excalibase-benchmark up -d --build
@echo "$(GREEN)✓ Enterprise benchmark services started$(NC)"
@$(MAKE) --no-print-directory benchmark-wait-ready
.PHONY: benchmark-down
benchmark-down: ## Stop enterprise benchmark Docker services
@echo "$(BLUE)🛑 Stopping enterprise benchmark services...$(NC)"
@docker compose -f scripts/docker-compose.benchmark.yml -p excalibase-benchmark down > /dev/null 2>&1 || true
@echo "$(GREEN)✓ Enterprise benchmark services stopped$(NC)"
.PHONY: benchmark-clean
benchmark-clean: ## Stop enterprise benchmark services and cleanup volumes
@echo "$(BLUE)🧹 Cleaning up enterprise benchmark environment...$(NC)"
@docker compose -f scripts/docker-compose.benchmark.yml -p excalibase-benchmark down -v --remove-orphans > /dev/null 2>&1 || true
@echo "$(GREEN)✓ Enterprise benchmark cleanup completed$(NC)"
.PHONY: benchmark-test
benchmark-test: benchmark-up benchmark-test-only ## Start services and run enterprise benchmark tests
@echo "$(GREEN)✓ Enterprise benchmark tests completed$(NC)"
.PHONY: benchmark-test-only
benchmark-test-only: ## Run enterprise benchmark tests (requires services to be running)
@echo "$(BLUE)🏢 Running Enterprise-Scale Benchmark Tests...$(NC)"
@$(MAKE) --no-print-directory benchmark-run-tests
.PHONY: benchmark-wait-ready
benchmark-wait-ready: ## Wait for enterprise benchmark services to be ready
@echo "$(BLUE)⏳ Waiting for enterprise benchmark services...$(NC)"
@echo "$(YELLOW)⚠️ Database initialization takes 2-5 minutes$(NC)"
@echo ""
@echo "$(BLUE)Waiting for PostgreSQL health check...$(NC)"
@sleep 5
@echo "$(BLUE)🔄 Waiting for database health check and application startup...$(NC)"
@for i in $$(seq 1 150); do \
if curl -s --connect-timeout 5 http://localhost:10002/graphql > /dev/null 2>&1; then \
echo "$(GREEN)✓ Enterprise GraphQL API ready with full dataset!$(NC)"; \
break; \
fi; \
if [ $$i -eq 150 ]; then \
echo "$(RED)❌ Application failed to start with enterprise dataset$(NC)"; \
echo "$(YELLOW)💡 Check logs: make benchmark-logs$(NC)"; \
exit 1; \
fi; \
if [ $$((i % 12)) -eq 0 ]; then \
printf "\n$(BLUE)Still waiting for services... ($$((i*5/60))min elapsed)$(NC)\n"; \
else \
printf "."; \
fi; \
sleep 5; \
done
@echo ""
@echo "$(GREEN)✓ All enterprise benchmark services ready!$(NC)"
.PHONY: benchmark-run-tests
benchmark-run-tests: ## Execute the enterprise benchmark test suite
@./scripts/e2e-benchmark.sh || (echo "$(RED)❌ Enterprise benchmark tests failed$(NC)" && exit 1)
.PHONY: benchmark-logs
benchmark-logs: ## Show enterprise benchmark service logs
@docker compose -f scripts/docker-compose.benchmark.yml -p excalibase-benchmark logs -f
.PHONY: benchmark-db-shell
benchmark-db-shell: ## Connect to enterprise benchmark PostgreSQL shell
@docker compose -f scripts/docker-compose.benchmark.yml -p excalibase-benchmark exec postgres psql -U excalibase_user -d excalibase_benchmark
.PHONY: benchmark-db-stats
benchmark-db-stats: ## Show enterprise benchmark database statistics
@echo "$(BLUE)📊 Enterprise Benchmark Database Statistics$(NC)"
@docker compose -f scripts/docker-compose.benchmark.yml -p excalibase-benchmark exec postgres psql -U excalibase_user -d excalibase_benchmark -c "
SELECT
schemaname,
tablename,
n_tup_ins as inserts,
n_tup_upd as updates,
n_tup_del as deletes,
n_live_tup as live_tuples,
n_dead_tup as dead_tuples,
pg_size_pretty(pg_total_relation_size(schemaname||'.'||tablename)) as table_size
FROM pg_stat_user_tables
WHERE schemaname = 'hana'
ORDER BY pg_total_relation_size(schemaname||'.'||tablename) DESC;"
# Force targets (ignore file existence)
.PHONY: docker-compose.yml scripts/initdb.sql scripts/docker-compose.benchmark.yml scripts/benchmark-initdb.sql scripts/e2e-benchmark.sh
# ─── Demo apps ───────────────────────────────────────────────────────────────
# UIs live in the SDK repo (excalibase-sdk-js) under examples/. The RLS demo
# stack (kanban + shopify with row-level security + role switching) lives in
# e2e/rls-demo/ — separate from the RLS-free jest e2e stack in e2e/study-cases/.
# Default sibling layout: ../excalibase-sdk-js relative to this repo.
DEMO_COMPOSE = e2e/rls-demo/docker-compose.rls-demo.yml
DEMO_PROJECT = excalibase-rls-demo
JIRA_DIR ?= ../excalibase-sdk-js/examples/jira-board
SHOP_DIR ?= ../excalibase-sdk-js/examples/storefront
.PHONY: demo-up demo-down demo-jira demo-jira-tokens demo-jira-build demo-shop demo-shop-tokens demo-shop-build
demo-up: ## Bring up the RLS demo stack (kanban + shopify with RLS + role switching)
@echo "$(BLUE)Starting RLS demo stack…$(NC)"
@docker compose -f $(DEMO_COMPOSE) -p $(DEMO_PROJECT) up -d
@echo "$(GREEN)Stack up. Waiting for excalibase-graphql healthcheck…$(NC)"
@for i in $$(seq 1 30); do \
if curl -sf http://localhost:10004/actuator/health > /dev/null 2>&1; then \
echo "$(GREEN)Ready at http://localhost:10004$(NC)"; exit 0; \
fi; sleep 2; \
done; echo "$(RED)graphql never became ready$(NC)"; exit 1
demo-down: ## Stop the RLS demo stack
@docker compose -f $(DEMO_COMPOSE) -p $(DEMO_PROJECT) down
# ─── Jira-board (kanban schema, role switching) ──────────────────────────────
demo-jira-tokens: ## Sign jira-board demo JWTs (run once after demo-up)
@test -d $(JIRA_DIR) || (echo "$(RED)$(JIRA_DIR) missing — set JIRA_DIR=… or check out excalibase-sdk-js as a sibling.$(NC)"; exit 1)
@cd $(JIRA_DIR) && (test -d node_modules || npm install --no-fund --no-audit) && npm run sign-tokens
demo-jira-build: ## Production-build jira-board
@cd $(JIRA_DIR) && (test -d node_modules || npm install --no-fund --no-audit) && npm run build
demo-jira: demo-up demo-jira-tokens ## End-to-end: stack up + tokens + jira-board dev server (port 5175)
@echo "$(GREEN)Vite dev server at http://localhost:5175 — Ctrl+C to stop.$(NC)"
@cd $(JIRA_DIR) && npm run dev
# ─── Storefront (shopify schema, role switching) ────────────────────────────
demo-shop-tokens: ## Sign storefront demo JWTs
@test -d $(SHOP_DIR) || (echo "$(RED)$(SHOP_DIR) missing — set SHOP_DIR=… or check out excalibase-sdk-js as a sibling.$(NC)"; exit 1)
@cd $(SHOP_DIR) && (test -d node_modules || npm install --no-fund --no-audit) && npm run sign-tokens
demo-shop-build: ## Production-build storefront
@cd $(SHOP_DIR) && (test -d node_modules || npm install --no-fund --no-audit) && npm run build
demo-shop: demo-up demo-shop-tokens ## End-to-end: stack up + tokens + storefront dev server (port 5176)
@echo "$(GREEN)Vite dev server at http://localhost:5176 — Ctrl+C to stop.$(NC)"
@cd $(SHOP_DIR) && npm run dev