Skip to content

Commit 2933154

Browse files
authored
Create consistent data sync IDs for applicability switch (#2223)
* Create consistent data sync IDs for applicability switch * Simplify * Check against hardcoded id
1 parent 3343b4f commit 2933154

File tree

2 files changed

+43
-22
lines changed

2 files changed

+43
-22
lines changed

src/Elastic.Markdown/Myst/Directives/AppliesSwitch/AppliesSwitchBlock.cs

Lines changed: 6 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
using Elastic.Documentation.AppliesTo;
66
using Elastic.Documentation.Configuration.Products;
7+
using Elastic.Documentation.Extensions;
78
using Elastic.Markdown.Diagnostics;
89
using Elastic.Markdown.Helpers;
910

@@ -67,23 +68,10 @@ public override void FinalizeAndValidate(ParserContext context)
6768

6869
public static string GenerateSyncKey(string appliesToDefinition, ProductsConfiguration productsConfiguration)
6970
{
70-
// Parse the YAML to get the ApplicableTo object, then use its hash
71-
// This ensures both simple syntax and YAML objects produce consistent sync keys
72-
try
73-
{
74-
var applicableTo = YamlSerialization.Deserialize<ApplicableTo>(appliesToDefinition, productsConfiguration);
75-
if (applicableTo != null)
76-
{
77-
// Use the object's hash for a consistent, unique identifier
78-
return $"applies-{System.Math.Abs(applicableTo.GetHashCode())}";
79-
}
80-
}
81-
catch
82-
{
83-
// If parsing fails, fall back to the original definition
84-
}
85-
86-
// Fallback to original definition if parsing fails
87-
return appliesToDefinition.Slugify().Replace(".", "-");
71+
var applicableTo = YamlSerialization.Deserialize<ApplicableTo>(appliesToDefinition, productsConfiguration);
72+
// Use ShortId.Create for a stable, deterministic hash based on the normalized ToString()
73+
// ToString() normalizes different YAML representations into a canonical form,
74+
// ensuring semantically equivalent definitions get the same sync key
75+
return $"applies-{ShortId.Create(applicableTo.ToString())}";
8876
}
8977
}

tests/Elastic.Markdown.Tests/Directives/ApplicabilitySwitchTests.cs

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -170,10 +170,7 @@ public void ParsesSyncKey()
170170

171171
// Verify all sync keys have the expected hash-based format
172172
foreach (var item in items)
173-
{
174173
item.SyncKey.Should().StartWith("applies-", "Sync key should start with 'applies-' prefix");
175-
item.SyncKey.Should().MatchRegex(@"^applies-\d+$", "Sync key should be in format 'applies-{hash}'");
176-
}
177174

178175
// Verify that different applies_to definitions produce different sync keys
179176
items[0].SyncKey.Should().NotBe(items[1].SyncKey, "Different applies_to definitions should produce different sync keys");
@@ -220,7 +217,43 @@ public void GeneratesConsistentSyncKeysForYamlObjects()
220217

221218
// Also verify the key has the expected format
222219
key1.Should().StartWith("applies-", "Sync key should start with 'applies-' prefix");
223-
key1.Should().MatchRegex(@"^applies-\d+$", "Sync key should be in format 'applies-{hash}'");
220+
key1.Should().MatchRegex(@"^applies-[0-9A-F]{8}$", "Sync key should be in format 'applies-{8 hex digits}'");
224221
}
225222
}
223+
224+
[Fact]
225+
public void GeneratesDeterministicSyncKeysAcrossMultipleRuns()
226+
{
227+
var expectedKeys = new Dictionary<string, string>
228+
{
229+
// These are the actual SHA256-based hashes that should never change
230+
{ "stack: ga 9.1", "applies-031B7112" },
231+
{ "stack: preview 9.0", "applies-361F73DC" },
232+
{ "ess: ga 8.11", "applies-32E204F7" },
233+
{ "deployment: { ece: ga 9.0, ess: ga 9.1 }", "applies-D099CDEF" },
234+
{ "serverless: all", "applies-A34B17C6" },
235+
};
236+
237+
foreach (var (definition, expectedKey) in expectedKeys)
238+
{
239+
var actualKey = AppliesItemBlock.GenerateSyncKey(definition, Block!.Build.ProductsConfiguration);
240+
241+
actualKey.Should().Be(expectedKey,
242+
$"The sync key for '{definition}' must match the expected value. " +
243+
$"If this fails, the hash algorithm has changed and will break sync IDs across builds!");
244+
245+
// Also verify multiple invocations in this run produce the same key
246+
var keys = Enumerable.Range(0, 5)
247+
.Select(_ => AppliesItemBlock.GenerateSyncKey(definition, Block!.Build.ProductsConfiguration))
248+
.ToList();
249+
250+
keys.Distinct().Should().HaveCount(1,
251+
$"All invocations for '{definition}' should produce identical keys");
252+
}
253+
254+
// Verify that different definitions produce different keys
255+
var allKeys = expectedKeys.Values.ToList();
256+
allKeys.Distinct().Should().HaveCount(expectedKeys.Count,
257+
"Different applies_to definitions must produce different sync keys");
258+
}
226259
}

0 commit comments

Comments
 (0)