Skip to content

Commit f38773a

Browse files
author
Madhan
committed
Add unit tests for DataStream add/remove backing index and timestamp meta-field merge
Covers the previously-untested added lines reported by codecov/patch: - DataStream.addBackingIndex (inserts at head, generation unchanged) - DataStream.removeBackingIndex validation (index not in stream; write index) - DataStreamFieldMapper merge validator (enable on merge allowed; disable once enabled rejected) Signed-off-by: Madhan <mkbn@amazon.com>
1 parent cf7b0a0 commit f38773a

2 files changed

Lines changed: 138 additions & 0 deletions

File tree

server/src/test/java/org/opensearch/cluster/metadata/DataStreamTests.java

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,71 @@ public void testRemoveBackingIndex() {
113113
}
114114
}
115115

116+
public void testAddBackingIndex() {
117+
int numBackingIndices = randomIntBetween(2, 32);
118+
String dataStreamName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
119+
120+
List<Index> indices = new ArrayList<>(numBackingIndices);
121+
for (int k = 1; k <= numBackingIndices; k++) {
122+
indices.add(new Index(DataStream.getDefaultBackingIndexName(dataStreamName, k), UUIDs.randomBase64UUID(random())));
123+
}
124+
DataStream original = new DataStream(dataStreamName, createTimestampField("@timestamp"), indices);
125+
126+
Index indexToAdd = new Index("index-to-add", UUIDs.randomBase64UUID(random()));
127+
DataStream updated = original.addBackingIndex(indexToAdd);
128+
assertThat(updated.getName(), equalTo(original.getName()));
129+
// adding a backing index does not change the generation (only rollover does)
130+
assertThat(updated.getGeneration(), equalTo(original.getGeneration()));
131+
assertThat(updated.getTimeStampField(), equalTo(original.getTimeStampField()));
132+
assertThat(updated.getIndices().size(), equalTo(numBackingIndices + 1));
133+
// the new index is added to the front so the existing write index stays last
134+
assertThat(updated.getIndices().get(0), equalTo(indexToAdd));
135+
assertThat(updated.getIndices().get(updated.getIndices().size() - 1), equalTo(original.getIndices().get(numBackingIndices - 1)));
136+
for (int k = 0; k < numBackingIndices; k++) {
137+
assertThat(updated.getIndices().get(k + 1), equalTo(original.getIndices().get(k)));
138+
}
139+
}
140+
141+
public void testRemoveBackingIndexThrowsExceptionIfIndexNotPartOfDataStream() {
142+
int numBackingIndices = randomIntBetween(2, 32);
143+
String dataStreamName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
144+
145+
List<Index> indices = new ArrayList<>(numBackingIndices);
146+
for (int k = 1; k <= numBackingIndices; k++) {
147+
indices.add(new Index(DataStream.getDefaultBackingIndexName(dataStreamName, k), UUIDs.randomBase64UUID(random())));
148+
}
149+
DataStream original = new DataStream(dataStreamName, createTimestampField("@timestamp"), indices);
150+
151+
Index standaloneIndex = new Index("index-foo", UUIDs.randomBase64UUID(random()));
152+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> original.removeBackingIndex(standaloneIndex));
153+
assertThat(e.getMessage(), equalTo("index [index-foo] is not part of data stream [" + dataStreamName + "]"));
154+
}
155+
156+
public void testRemoveBackingIndexThrowsExceptionIfRemovingWriteIndex() {
157+
int numBackingIndices = randomIntBetween(2, 32);
158+
int writeIndexPosition = numBackingIndices - 1;
159+
String dataStreamName = randomAlphaOfLength(10).toLowerCase(Locale.ROOT);
160+
161+
List<Index> indices = new ArrayList<>(numBackingIndices);
162+
for (int k = 1; k <= numBackingIndices; k++) {
163+
indices.add(new Index(DataStream.getDefaultBackingIndexName(dataStreamName, k), UUIDs.randomBase64UUID(random())));
164+
}
165+
DataStream original = new DataStream(dataStreamName, createTimestampField("@timestamp"), indices);
166+
167+
Index writeIndex = indices.get(writeIndexPosition);
168+
IllegalArgumentException e = expectThrows(IllegalArgumentException.class, () -> original.removeBackingIndex(writeIndex));
169+
assertThat(
170+
e.getMessage(),
171+
equalTo(
172+
"cannot remove backing index ["
173+
+ writeIndex.getName()
174+
+ "] of data stream ["
175+
+ dataStreamName
176+
+ "] because it is the write index"
177+
)
178+
);
179+
}
180+
116181
public void testDefaultBackingIndexName() {
117182
// this test does little more than flag that changing the default naming convention for backing indices
118183
// will also require changing a lot of hard-coded values in REST tests and docs

server/src/test/java/org/opensearch/index/mapper/DataStreamFieldMapperTests.java

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,79 @@ public void testDeeplyNestedCustomTimestampField() throws Exception {
113113
);
114114
}
115115

116+
public void testEnableOnMappingMergeIsAllowed() throws Exception {
117+
MapperService mapperService = createIndex("test").mapperService();
118+
119+
// an index that starts out without the _data_stream_timestamp meta field (the default disabled state)
120+
mapperService.merge(
121+
"_doc",
122+
new CompressedXContent("{\"_doc\":{\"properties\":{\"@timestamp\":{\"type\":\"date\"}}}}"),
123+
MapperService.MergeReason.MAPPING_UPDATE
124+
);
125+
126+
// enabling the meta field on a subsequent merge is allowed (this is how an existing index is adapted into a backing index)
127+
String enableMapping = XContentFactory.jsonBuilder()
128+
.startObject()
129+
.startObject("_doc")
130+
.startObject("_data_stream_timestamp")
131+
.field("enabled", true)
132+
.endObject()
133+
.endObject()
134+
.endObject()
135+
.toString();
136+
DocumentMapper merged = mapperService.merge(
137+
"_doc",
138+
new CompressedXContent(enableMapping),
139+
MapperService.MergeReason.MAPPING_UPDATE
140+
);
141+
142+
// the meta field is now enabled, so the timestamp validation in postParse is active
143+
MapperException exception = expectThrows(
144+
MapperException.class,
145+
() -> merged.parse(
146+
new SourceToParse(
147+
"test",
148+
"1",
149+
BytesReference.bytes(XContentFactory.jsonBuilder().startObject().endObject()),
150+
MediaTypeRegistry.JSON
151+
)
152+
)
153+
);
154+
assertThat(exception.getCause().getMessage(), containsString("documents must contain a single-valued timestamp field"));
155+
}
156+
157+
public void testDisableOnceEnabledIsRejected() throws Exception {
158+
MapperService mapperService = createIndex("test").mapperService();
159+
160+
// start with the meta field enabled
161+
String enableMapping = XContentFactory.jsonBuilder()
162+
.startObject()
163+
.startObject("_doc")
164+
.startObject("_data_stream_timestamp")
165+
.field("enabled", true)
166+
.endObject()
167+
.endObject()
168+
.endObject()
169+
.toString();
170+
mapperService.merge("_doc", new CompressedXContent(enableMapping), MapperService.MergeReason.MAPPING_UPDATE);
171+
172+
// attempting to disable it again on a subsequent merge is rejected by the merge validator
173+
String disableMapping = XContentFactory.jsonBuilder()
174+
.startObject()
175+
.startObject("_doc")
176+
.startObject("_data_stream_timestamp")
177+
.field("enabled", false)
178+
.endObject()
179+
.endObject()
180+
.endObject()
181+
.toString();
182+
IllegalArgumentException exception = expectThrows(
183+
IllegalArgumentException.class,
184+
() -> mapperService.merge("_doc", new CompressedXContent(disableMapping), MapperService.MergeReason.MAPPING_UPDATE)
185+
);
186+
assertThat(exception.getMessage(), containsString("Cannot update parameter [enabled] from [true] to [false]"));
187+
}
188+
116189
private void assertDataStreamFieldMapper(String mapping, String timestampFieldName) throws Exception {
117190
DocumentMapper mapper = createIndex("test").mapperService()
118191
.merge("_doc", new CompressedXContent(mapping), MapperService.MergeReason.MAPPING_UPDATE);

0 commit comments

Comments
 (0)