Skip to content

Commit 331eba3

Browse files
committed
Show detecting incorrect write order on SBE flyweight.
Adds a new schema and test, which is referenced from the SBE Warnings page. The aim is to show how precedence checks in SBE `1.30.0` can help prevent some incorrect usages of SBE flyweights.
1 parent 5bc3e2c commit 331eba3

File tree

3 files changed

+98
-4
lines changed

3 files changed

+98
-4
lines changed

sbe-core/src/test/java/com/aeroncookbook/sbe/SbeTests.java

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -16,14 +16,16 @@
1616

1717
package com.aeroncookbook.sbe;
1818

19-
import static org.junit.jupiter.api.Assertions.assertEquals;
20-
21-
import java.nio.ByteBuffer;
22-
2319
import org.agrona.concurrent.UnsafeBuffer;
2420
import org.junit.jupiter.api.Assertions;
2521
import org.junit.jupiter.api.Test;
2622

23+
import java.lang.reflect.Field;
24+
import java.nio.ByteBuffer;
25+
26+
import static org.junit.jupiter.api.Assertions.assertEquals;
27+
import static org.junit.jupiter.api.Assertions.assertThrows;
28+
2729
public class SbeTests
2830
{
2931

@@ -175,6 +177,32 @@ public void dataCanBeCorrupted()
175177
Assertions.assertNotEquals(DATA_2, decoder.data2());
176178
}
177179

180+
@Test
181+
public void corruptionCanBeDetected() throws NoSuchFieldException, IllegalAccessException
182+
{
183+
assumePrecedenceChecksAreEnabled();
184+
185+
final SampleCorruptionDetectedEncoder encoder = new SampleCorruptionDetectedEncoder();
186+
final MessageHeaderEncoder messageHeaderEncoder = new MessageHeaderEncoder();
187+
final ByteBuffer byteBuffer = ByteBuffer.allocateDirect(128);
188+
final UnsafeBuffer directBuffer = new UnsafeBuffer(byteBuffer);
189+
190+
encoder.wrapAndApplyHeader(directBuffer, 0, messageHeaderEncoder);
191+
final IllegalStateException exception =
192+
assertThrows(IllegalStateException.class, () -> encoder.data2(DATA_2));
193+
final String expectedErrorFragment =
194+
"Illegal field access order. Cannot access field \"data2\" in state: V0_BLOCK.";
195+
Assertions.assertTrue(exception.getMessage().contains(expectedErrorFragment));
196+
}
197+
198+
private static void assumePrecedenceChecksAreEnabled() throws NoSuchFieldException, IllegalAccessException
199+
{
200+
final Field enabledField = SampleCorruptionDetectedEncoder.class
201+
.getDeclaredField("SBE_ENABLE_PRECEDENCE_CHECKS");
202+
enabledField.setAccessible(true);
203+
Assertions.assertTrue((boolean)enabledField.get(null));
204+
}
205+
178206
@Test
179207
public void dataCanBeReadCorrectlyWhenWrittenCorrectly()
180208
{

sbe-protocol/build.gradle.kts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,25 @@ tasks {
3535
outputs.dir(generatedDir)
3636
}
3737

38+
task("generateCodecsWithPrecedeceChecks", JavaExec::class) {
39+
group = "sbe"
40+
val codecsFile = "src/main/resources/precedence-checked-messages.xml"
41+
val sbeFile = "src/main/resources/sbe/sbe.xsd"
42+
inputs.files(codecsFile, sbeFile)
43+
outputs.dir(generatedDir)
44+
classpath = codecGeneration
45+
mainClass.set("uk.co.real_logic.sbe.SbeTool")
46+
args = listOf(codecsFile)
47+
systemProperties["sbe.output.dir"] = generatedDir
48+
systemProperties["sbe.target.language"] = "Java"
49+
systemProperties["sbe.validation.xsd"] = sbeFile
50+
systemProperties["sbe.validation.stop.on.error"] = "true"
51+
systemProperties["sbe.generate.precedence.checks"] = "true"
52+
outputs.dir(generatedDir)
53+
}
54+
3855
compileJava {
3956
dependsOn("generateCodecs")
57+
dependsOn("generateCodecsWithPrecedeceChecks")
4058
}
4159
}
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
2+
<!--
3+
~ Copyright 2019-2023 Adaptive Financial Consulting Ltd.
4+
~
5+
~ Licensed under the Apache License, Version 2.0 (the "License");
6+
~ you may not use this file except in compliance with the License.
7+
~ You may obtain a copy of the License at
8+
~
9+
~ https://www.apache.org/licenses/LICENSE-2.0
10+
~
11+
~ Unless required by applicable law or agreed to in writing, software
12+
~ distributed under the License is distributed on an "AS IS" BASIS,
13+
~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
~ See the License for the specific language governing permissions and
15+
~ limitations under the License.
16+
-->
17+
18+
<sbe:messageSchema xmlns:sbe="http://fixprotocol.io/2016/sbe"
19+
package="com.aeroncookbook.sbe"
20+
id="689"
21+
version="1"
22+
semanticVersion="0.1"
23+
description="Sample SBE Messages"
24+
byteOrder="littleEndian">
25+
<types>
26+
<composite name="messageHeader" description="Message identifiers and length of message root">
27+
<type name="blockLength" primitiveType="uint16"/>
28+
<type name="templateId" primitiveType="uint16"/>
29+
<type name="schemaId" primitiveType="uint16"/>
30+
<type name="version" primitiveType="uint16"/>
31+
</composite>
32+
<composite name="varStringEncoding">
33+
<type name="length" primitiveType="uint32" maxValue="1073741824"/>
34+
<type name="varData" primitiveType="uint8" length="0" characterEncoding="UTF-8"/>
35+
</composite>
36+
</types>
37+
<types>
38+
<type name="Sequence" primitiveType="int64"/>
39+
</types>
40+
41+
<sbe:message name="SampleCorruptionDetected" id="1002" description="Corruption sample">
42+
<field name="sequence1" id="1" type="Sequence"/>
43+
<field name="sequence2" id="2" type="Sequence"/>
44+
<data name="data1" id="3" type="varStringEncoding"/>
45+
<data name="data2" id="4" type="varStringEncoding"/>
46+
</sbe:message>
47+
48+
</sbe:messageSchema>

0 commit comments

Comments
 (0)