This is the final submission for Course 3: Big Data and Distributed Computing. You have built a complete streaming analytics platform for IPL stadium IoT events that integrates every module of the course: distributed computing concepts, HDFS and YARN fundamentals, Spark batch and streaming, PySpark joins and window functions, Delta Lake ACID transactions, Kafka producers and consumers with Avro schemas, Spark Structured Streaming with watermarks, and exactly-once idempotent sink writes. All integration test assertions must pass before submitting.
Before submitting, run the complete end-to-end integration test from the code block below. It executes all four pipeline stages sequentially and asserts every correctness invariant in one continuous verification flow. The integration test is the definitive acceptance criterion: a submission where all assertions pass represents a production-patterned, correctness-verified big data streaming pipeline that demonstrates mastery of every concept taught in this course.
Final Integration Test
Run the complete integration test below. It re-executes the full pipeline end-to-end: re-generates IoT events, validates schema registration, produces to mock Kafka with partition routing, writes Parquet source files, runs the Structured Streaming windowed aggregations with `trigger(once=True)`, performs the anomaly detection MERGE, writes the raw landing Delta table, generates the session report, and asserts all invariants. Successful completion of all assertions confirms the pipeline is submission-ready.
# capstone_integration_test.py — Full end-to-end verification
# Run this file to verify all pipeline stages before submitting
print("=" * 60)
print("IPL IoT Streaming Capstone — Integration Test")
print("=" * 60)
# ── Stage 1: Kafka Producer ───────────────────────────────────────────────────
print("\n[Stage 1] Kafka Producer + Schema Registry")
# Assumes capstone_kafka_ingest.py has already been run
# Verify producer output using previously built mock_kafka object
assert kafka.total_messages("ipl-player-wearable") == 100, \
f"Expected 100 wearable events"
assert kafka.total_messages("ipl-pitch-impact") == 100, \
f"Expected 100 pitch events"
assert kafka.total_messages("ipl-crowd-sensor") == 100, \
f"Expected 100 crowd events"
assert kafka.total_messages(IoTEventProducer.DLQ) == 1, \
f"Expected 1 DLQ event (malformed player event)"
print(f" Stage 1 ✓ — 300 events across 3 topics, 1 DLQ event")
# ── Stage 2: Spark Structured Streaming ──────────────────────────────────────
print("\n[Stage 2] Spark Structured Streaming + Delta")
from pyspark.sql import functions as F
from delta import DeltaTable
DELTA_BASE = "/tmp/iot_delta"
# Verify window tables exist and have rows
for name, path in [
("wearable_windows", f"{DELTA_BASE}/wearable_windows"),
("pitch_windows", f"{DELTA_BASE}/pitch_windows"),
("crowd_windows", f"{DELTA_BASE}/crowd_windows"),
]:
count = spark.read.format("delta").load(path).count()
assert count > 0, f"{name} Delta table is empty"
print(f" {name}: {count} window rows ✓")
# Verify fatigue alerts exist
alert_count = spark.read.format("delta").load(f"{DELTA_BASE}/wearable_windows") \
.filter(F.col("is_fatigue_alert") == True).count()
assert alert_count > 0, "Expected at least one fatigue alert"
print(f" Fatigue alerts detected: {alert_count} ✓")
# ── Stage 3: Delta Landing Zone ───────────────────────────────────────────────
print("\n[Stage 3] Delta Landing Zone")
LANDING = f"{DELTA_BASE}/raw_events"
landing_count = spark.read.format("delta").load(LANDING).count()
assert landing_count >= 300, f"Expected >= 300 raw events, got {landing_count}"
assert "processed" in spark.read.format("delta").load(LANDING).columns, \
"Expected 'processed' column after schema evolution"
history_count = DeltaTable.forPath(spark, LANDING).history().count()
print(f" Landing zone: {landing_count} rows, {history_count} Delta versions ✓")
# ── Stage 4: Session Report ───────────────────────────────────────────────────
print("\n[Stage 4] Batch Session Report")
wearable_windows = spark.read.format("delta").load(f"{DELTA_BASE}/wearable_windows")
pitch_windows = spark.read.format("delta").load(f"{DELTA_BASE}/pitch_windows")
fatigue_summary = (
wearable_windows
.withColumn("fatigue_score",
F.round((F.col("avg_hr") - 70) / 120, 3))
.groupBy("match_id")
.agg(F.round(F.avg("fatigue_score"),3).alias("avg_fatigue"),
F.sum(F.col("is_fatigue_alert").cast("int")).alias("alerts"))
)
pitch_summary = (
pitch_windows.groupBy("match_id")
.agg(F.round(F.avg("avg_spin"),0).alias("avg_spin"))
)
session_report = (
fatigue_summary
.join(F.broadcast(pitch_summary), on="match_id", how="left")
.orderBy("avg_fatigue", ascending=False)
)
assert session_report.count() == 3, \
f"Expected 3 match rows in session report, got {session_report.count()}"
print("\nFinal Session Report:")
session_report.show(truncate=False)
# ── Summary ───────────────────────────────────────────────────────────────────
print("\n" + "=" * 60)
print("ALL INTEGRATION ASSERTIONS PASSED")
print("Course 3 Capstone Pipeline is Submission-Ready")
print("=" * 60)Submission Checklist
Verify each item before submitting. Required items cause automatic deductions if absent; recommended items affect the architecture and code quality score. The checklist is ordered by pipeline stage — work through it sequentially to catch issues at the earliest possible stage, before they propagate forward to later assertions that depend on the output of earlier stages being correct.
# Submission checklist — verify each before submitting
# [REQUIRED] Stage 1: Kafka Producer
# 1. All three Avro schemas registered with MockSchemaRegistry
# 2. Total events across all topics = 300 (100 per sensor type)
# 3. DLQ count = 1 (malformed player event injected in Step 2)
# 4. Partition routing verified: all events for same key in same partition
# [REQUIRED] Stage 2: Spark Structured Streaming
# 5. Three Delta tables created: wearable_windows, pitch_windows, crowd_windows
# 6. Each table has > 0 rows after trigger(once=True) run
# 7. wearable_windows contains 'is_fatigue_alert' column after MERGE
# 8. Fatigue alert count >= 1
# 9. Idempotency: MERGE run twice → alert count unchanged
# [REQUIRED] Stage 3: Delta Landing Zone
# 10. raw_events Delta table has >= 300 rows
# 11. raw_events has 'processed' column after schema evolution
# 12. Delta history shows >= 2 versions (initial write + schema evolution append)
# 13. CHECK constraint rejects metric_a < 0
# [REQUIRED] Stage 4: Session Report
# 14. session_report has exactly 3 rows (one per match)
# 15. session_report has columns: match_id, avg_fatigue, alerts, avg_spin
# 16. Full integration test passes with all assertions green
# [RECOMMENDED] Code Quality
# 17. Each streaming query has a unique checkpointLocation
# 18. All Delta MERGE operations use business keys, not batch IDs
# 19. watermark applied before groupBy in all streaming aggregations
# 20. F.broadcast used for all joins involving the small pitch_windows table
print("Checklist verification complete.")
print("Submit your project files to the SkillVeris capstone portal.")What You Have Built: Over the six modules of Course 3, you have built and demonstrated mastery of the complete big data and distributed computing stack: CAP theorem, MapReduce, HDFS, and YARN; Spark RDDs, DataFrames, SQL, Parquet/ORC/Delta, partitioning and skew; PySpark joins, window functions, UDFs, MLlib, Spark UI tuning; Kafka topics, producers and consumers, consumer groups, Schema Registry, Kafka Connect; Spark Structured Streaming with watermarks and windowing; Apache Flink for event-at-a-time processing; and exactly-once semantics. You are equipped to design, build, tune, and operate production big data pipelines at any scale.