blob: 34df6d7330d017653450f2a23a6c17e124597f63 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
namespace Apache.Ignite.Core.Tests.Binary
{
using System;
using System.Linq;
using Apache.Ignite.Core.Binary;
using Apache.Ignite.Core.Cache.Configuration;
using Apache.Ignite.Core.Cache.Query;
using Apache.Ignite.Core.Impl;
using Apache.Ignite.Core.Impl.Binary;
using NUnit.Framework;
/// <summary>
/// Tests binary footer integrity (field offsets).
/// Writes objects of various sizes to test schema compaction
/// (where field offsets can be stored as 1, 2 or 4 bytes).
/// </summary>
public class BinaryFooterTest
{
/// <summary>
/// Tears down the test.
/// </summary>
[TearDown]
public void TearDown()
{
Ignition.StopAll(true);
}
/// <summary>
/// Tests full footers in offline mode.
/// </summary>
[Test]
public void TestFullFooterOffline()
{
// Register type to avoid unregistered type name in binary object.
// Use new marshaller to read and write to avoid schema caching.
TestOffsets(() => new Marshaller(new BinaryConfiguration(typeof(OffsetTest))
{
// Compact footers do not work in offline mode.
CompactFooter = false
}));
}
/// <summary>
/// Tests the full footer online.
/// </summary>
[Test]
public void TestFullFooterOnline()
{
var ignite = Ignition.Start(new IgniteConfiguration(TestUtils.GetTestConfiguration())
{
BinaryConfiguration = new BinaryConfiguration
{
CompactFooter = false
}
});
TestOffsets(() => ((Ignite) ignite).Marshaller);
}
/// <summary>
/// Tests the full footer online.
/// </summary>
[Test]
public void TestCompactFooterOnline()
{
var ignite = Ignition.Start(TestUtils.GetTestConfiguration());
TestOffsets(() => ((Ignite) ignite).Marshaller);
}
/// <summary>
/// Tests the offsets.
/// </summary>
private static void TestOffsets(Func<Marshaller> getMarsh)
{
// Corner cases are byte/sbyte/short/ushort max values.
foreach (var i in new[] {1, sbyte.MaxValue, byte.MaxValue, short.MaxValue, ushort.MaxValue})
{
foreach (var j in new[] {-1, 0, 1})
{
var arrSize = i + j;
var dt = new OffsetTest
{
Arr = Enumerable.Range(0, arrSize).Select(x => (byte) x).ToArray(),
Int = arrSize
};
var bytes = getMarsh().Marshal(dt);
var res = getMarsh().Unmarshal<OffsetTest>(bytes);
var binRes = getMarsh().Unmarshal<IBinaryObject>(bytes, BinaryMode.ForceBinary);
var binFieldRes = new OffsetTest
{
Arr = binRes.GetField<byte[]>("arr"),
Int = binRes.GetField<int>("int")
};
foreach (var r in new[] {res, binRes.Deserialize<OffsetTest>(), binFieldRes})
{
Assert.AreEqual(dt.Arr, r.Arr);
Assert.AreEqual(dt.Int, r.Int);
}
TestSql(dt, getMarsh());
}
}
}
/// <summary>
/// Tests SQL query, which verifies Java side of things.
/// </summary>
private static void TestSql(OffsetTest dt, Marshaller marsh)
{
var ignite = marsh.Ignite;
if (ignite == null)
{
return;
}
var cache = ignite.GetIgnite().GetOrCreateCache<int, OffsetTest>(
new CacheConfiguration("offs", new QueryEntity(typeof(int), typeof(OffsetTest))));
// Cache operation.
cache[1] = dt;
Assert.AreEqual(dt.Int, cache[1].Int);
Assert.AreEqual(dt.Arr, cache[1].Arr);
// SQL: read field on Java side to ensure correct offset handling.
var res = cache.Query(new SqlFieldsQuery("select int from OffsetTest")).GetAll()[0][0];
Assert.AreEqual(dt.Int, (int) res);
}
/// <summary>
/// Offset test.
/// </summary>
private class OffsetTest : IBinarizable
{
[QuerySqlField]
public byte[] Arr; // Array to enforce field offset.
[QuerySqlField]
public int Int; // Value at offset.
public void WriteBinary(IBinaryWriter writer)
{
writer.WriteByteArray("arr", Arr);
writer.WriteInt("int", Int);
}
public void ReadBinary(IBinaryReader reader)
{
// Read in different order to enforce full schema scan.
Int = reader.ReadInt("int");
Arr = reader.ReadByteArray("arr");
}
}
}
}