Repository: zalando/nakadi
Issue: Nakadi silently overrides metadata.flow_id

When publishing an event, if the header `X-Flow-Id` is not provided, then Nakadi will silently override this field with a randomly generated value.

I would expect Nakadi not to override it, if it was provided, since it's mentioned in the API that "No preexisting value might be changed".

> 1. Once the validation succeeded, the content of the Event is updated according to the
>        enrichment rules in the order the rules are defined in the `EventType`.  No preexisting
>        value might be changed (even if added by an enrichment rule). Violations on this will force
>        the immediate **rejection** of the Event. The invalid overwrite attempt will be included in
>        the item's `BatchItemResponse` object.

It should either reject such event (which doesn't make much sense) or keep it, if present.


Changed files:
src/main/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategy.java
src/test/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategyTest.java

diff --git a/src/main/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategy.java b/src/main/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategy.java
index 145545f9c..ec4e154fe 100644
--- a/src/main/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategy.java
+++ b/src/main/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategy.java
@@ -30,7 +30,9 @@ public class MetadataEnrichmentStrategy implements EnrichmentStrategy {
     }
 
     private void setFlowId(final JSONObject metadata) {
-        metadata.put("flow_id", FlowIdUtils.peek());
+        if ("".equals(metadata.optString("flow_id"))) {
+            metadata.put("flow_id", FlowIdUtils.peek());
+        }
     }
 
     private void setEventTypeName(final JSONObject metadata, final EventType eventType) {
diff --git a/src/test/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategyTest.java b/src/test/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategyTest.java
index 768b9547c..642ec2568 100644
--- a/src/test/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategyTest.java
+++ b/src/test/java/org/zalando/nakadi/enrichment/MetadataEnrichmentStrategyTest.java
@@ -90,6 +90,47 @@ public class MetadataEnrichmentStrategyTest {
         assertThat(batch.getEvent().getJSONObject("metadata").getString("flow_id"), equalTo(flowId));
     }
 
+    @Test
+    public void whenFlowIdIsPresentDoNotOverride() throws Exception {
+        final EventType eventType = buildDefaultEventType();
+        final JSONObject event = buildBusinessEvent();
+        event.getJSONObject("metadata").put("flow_id", "something");
+        final BatchItem batch = createBatchItem(event);
+
+        FlowIdUtils.push("something-else");
+        strategy.enrich(batch, eventType);
+
+        assertThat(batch.getEvent().getJSONObject("metadata").getString("flow_id"), equalTo("something"));
+    }
+
+    @Test
+    public void whenFlowIsEmptyStringOverrideIt() throws Exception {
+        final EventType eventType = buildDefaultEventType();
+        final JSONObject event = buildBusinessEvent();
+        event.getJSONObject("metadata").put("flow_id", "");
+        final BatchItem batch = createBatchItem(event);
+
+        final String flowId = randomString();
+        FlowIdUtils.push(flowId);
+        strategy.enrich(batch, eventType);
+
+        assertThat(batch.getEvent().getJSONObject("metadata").getString("flow_id"), equalTo(flowId));
+    }
+
+    @Test
+    public void whenFlowIsNullOverrideIt() throws Exception {
+        final EventType eventType = buildDefaultEventType();
+        final JSONObject event = buildBusinessEvent();
+        event.getJSONObject("metadata").put("flow_id", (Object)null);
+        final BatchItem batch = createBatchItem(event);
+
+        final String flowId = randomString();
+        FlowIdUtils.push(flowId);
+        strategy.enrich(batch, eventType);
+
+        assertThat(batch.getEvent().getJSONObject("metadata").getString("flow_id"), equalTo(flowId));
+    }
+
     @Test
     public void setPartition() throws Exception {
         final EventType eventType = buildDefaultEventType();