Skip to content

Commit 6379ad3

Browse files
authored
Merge pull request #249 from real-logic/chore/sbe-precedence-checks
Add SBE precedence checks test for SBE warnings page
2 parents 1e93fcc + 331eba3 commit 6379ad3

File tree

5 files changed

+125
-31
lines changed

5 files changed

+125
-31
lines changed

gradle/libs.versions.toml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ junitVersion = "5.10.1"
33
junitPlatformVersion = "1.10.1"
44
checkstyleVersion = "10.12.5"
55
aeronVersion = "1.42.1"
6-
sbeVersion = "1.29.0"
7-
agronaVersion = "1.19.2"
6+
sbeVersion = "1.30.0"
7+
agronaVersion = "1.20.0"
88
slf4jVersion = "2.0.9"
99
logbackVersion = "1.4.14"
1010
mockitoVersion = "5.8.0"

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

Lines changed: 55 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -16,20 +16,22 @@
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

3032
public static final String TEMPLATE_IDS_DO_NOT_MATCH = "Template ids do not match";
31-
public static final String MESSAGE_2 = "a message";
32-
public static final String MESSAGE_1 = "message a";
33+
public static final String DATA_1 = "foo";
34+
public static final String DATA_2 = "bar";
3335

3436
@Test
3537
public void canWriteReadSampleA()
@@ -42,7 +44,7 @@ public void canWriteReadSampleA()
4244
encoder.wrapAndApplyHeader(directBuffer, 0, messageHeaderEncoder);
4345
encoder.sequence(123L);
4446
encoder.enumField(SampleEnum.VALUE_1);
45-
encoder.message(MESSAGE_1);
47+
encoder.message(DATA_1);
4648

4749
final SampleSimpleDecoder decoder = new SampleSimpleDecoder();
4850
final MessageHeaderDecoder headerDecoder = new MessageHeaderDecoder();
@@ -64,7 +66,7 @@ public void canWriteReadSampleA()
6466

6567
assertEquals(123, decoder.sequence());
6668
assertEquals(SampleEnum.VALUE_1, decoder.enumField());
67-
assertEquals(MESSAGE_1, decoder.message());
69+
assertEquals(DATA_1, decoder.message());
6870
}
6971

7072
@Test
@@ -77,15 +79,15 @@ public void canWriteReadSampleAWithoutHeader()
7779
encoder.wrap(directBuffer, 0);
7880
encoder.sequence(123L);
7981
encoder.enumField(SampleEnum.VALUE_1);
80-
encoder.message(MESSAGE_1);
82+
encoder.message(DATA_1);
8183

8284
final SampleSimpleDecoder decoder = new SampleSimpleDecoder();
8385

8486
decoder.wrap(directBuffer, 0, decoder.sbeBlockLength(), decoder.sbeSchemaVersion());
8587

8688
assertEquals(123, decoder.sequence());
8789
assertEquals(SampleEnum.VALUE_1, decoder.enumField());
88-
assertEquals(MESSAGE_1, decoder.message());
90+
assertEquals(DATA_1, decoder.message());
8991
}
9092

9193
@Test
@@ -102,12 +104,12 @@ public void canWriteReadSampleRepeatGroups()
102104
groupEncoder.next();
103105
groupEncoder.groupField1(1);
104106
groupEncoder.groupField2(2);
105-
groupEncoder.groupField3(MESSAGE_2);
107+
groupEncoder.groupField3(DATA_2);
106108
groupEncoder.next();
107109
groupEncoder.groupField1(1);
108110
groupEncoder.groupField2(2);
109-
groupEncoder.groupField3(MESSAGE_2);
110-
encoder.message(MESSAGE_1);
111+
groupEncoder.groupField3(DATA_2);
112+
encoder.message(DATA_1);
111113

112114

113115
final SampleGroupDecoder decoder = new SampleGroupDecoder();
@@ -132,9 +134,9 @@ public void canWriteReadSampleRepeatGroups()
132134
{
133135
assertEquals(1, groupDecoder.groupField1());
134136
assertEquals(2, groupDecoder.groupField2());
135-
assertEquals(MESSAGE_2, groupDecoder.groupField3());
137+
assertEquals(DATA_2, groupDecoder.groupField3());
136138
}
137-
assertEquals(MESSAGE_1, decoder.message());
139+
assertEquals(DATA_1, decoder.message());
138140
}
139141

140142
@Test
@@ -146,8 +148,8 @@ public void dataCanBeCorrupted()
146148
final UnsafeBuffer directBuffer = new UnsafeBuffer(byteBuffer);
147149

148150
encoder.wrapAndApplyHeader(directBuffer, 0, messageHeaderEncoder);
149-
encoder.message2(MESSAGE_2);
150-
encoder.message1(MESSAGE_1);
151+
encoder.data2(DATA_2);
152+
encoder.data1(DATA_1);
151153
encoder.sequence1(123L);
152154
encoder.sequence2(321L);
153155

@@ -170,9 +172,35 @@ public void dataCanBeCorrupted()
170172
decoder.wrap(directBuffer, bufferOffset, actingBlockLength, actingVersion);
171173

172174
assertEquals(123, decoder.sequence1());
173-
Assertions.assertNotEquals(MESSAGE_1, decoder.message1());
175+
Assertions.assertNotEquals(DATA_1, decoder.data1());
174176
assertEquals(321, decoder.sequence2());
175-
Assertions.assertNotEquals(MESSAGE_2, decoder.message2());
177+
Assertions.assertNotEquals(DATA_2, decoder.data2());
178+
}
179+
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));
176204
}
177205

178206
@Test
@@ -186,8 +214,8 @@ public void dataCanBeReadCorrectlyWhenWrittenCorrectly()
186214
encoder.wrapAndApplyHeader(directBuffer, 0, messageHeaderEncoder);
187215
encoder.sequence1(123L);
188216
encoder.sequence2(321L);
189-
encoder.message1(MESSAGE_1);
190-
encoder.message2(MESSAGE_2);
217+
encoder.data1(DATA_1);
218+
encoder.data2(DATA_2);
191219

192220
final SampleCorruptionDecoder decoder = new SampleCorruptionDecoder();
193221
final MessageHeaderDecoder headerDecoder = new MessageHeaderDecoder();
@@ -209,8 +237,8 @@ public void dataCanBeReadCorrectlyWhenWrittenCorrectly()
209237

210238
assertEquals(123, decoder.sequence1());
211239
assertEquals(321, decoder.sequence2());
212-
assertEquals(MESSAGE_1, decoder.message1());
213-
assertEquals(MESSAGE_2, decoder.message2());
240+
assertEquals(DATA_1, decoder.data1());
241+
assertEquals(DATA_2, decoder.data2());
214242
}
215243

216244

@@ -225,8 +253,8 @@ public void nullStringReturnsAsEmptyString()
225253
encoder.wrapAndApplyHeader(directBuffer, 0, messageHeaderEncoder);
226254
encoder.sequence1(123L);
227255
encoder.sequence2(321L);
228-
encoder.message1(MESSAGE_1);
229-
encoder.message2(null);
256+
encoder.data1(DATA_1);
257+
encoder.data2(null);
230258

231259
final SampleCorruptionDecoder decoder = new SampleCorruptionDecoder();
232260
final MessageHeaderDecoder headerDecoder = new MessageHeaderDecoder();
@@ -248,7 +276,7 @@ public void nullStringReturnsAsEmptyString()
248276

249277
assertEquals(123, decoder.sequence1());
250278
assertEquals(321, decoder.sequence2());
251-
assertEquals(MESSAGE_1, decoder.message1());
252-
assertEquals("", decoder.message2());
279+
assertEquals(DATA_1, decoder.data1());
280+
assertEquals("", decoder.data2());
253281
}
254282
}

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
}

sbe-protocol/src/main/resources/messages.xml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,8 +61,8 @@
6161
<sbe:message name="SampleCorruption" id="2" description="Corruption sample">
6262
<field name="sequence1" id="1" type="Sequence"/>
6363
<field name="sequence2" id="2" type="Sequence"/>
64-
<data name="message1" id="3" type="varStringEncoding"/>
65-
<data name="message2" id="4" type="varStringEncoding"/>
64+
<data name="data1" id="3" type="varStringEncoding"/>
65+
<data name="data2" id="4" type="varStringEncoding"/>
6666
</sbe:message>
6767

6868
<sbe:message name="SampleGroup" id="3" description="Sample with group">
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)