blob: f1e70ed1cf64779637e9b6526f5e152cd2724c51 [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.
*/
#include <sstream>
#include <algorithm>
#include <boost/test/unit_test.hpp>
#include "ignite/common/utils.h"
#include "ignite/ignite.h"
#include "ignite/ignition.h"
#include "ignite/test_utils.h"
#include "ignite/ignite_binding_context.h"
#include "ignite/cache/cache_entry_processor.h"
#include "ignite/test_utils.h"
using namespace boost::unit_test;
using namespace ignite;
using namespace ignite::cache;
using namespace ignite::common;
/**
* CacheEntryModifier class for invoke tests.
*/
class CacheEntryModifier : public CacheEntryProcessor<int, int, int, int>
{
public:
/**
* Constructor.
*/
CacheEntryModifier() : num(0)
{
// No-op.
}
/**
* Constructor.
*
* @param num Number to substract from the entry.
*/
CacheEntryModifier(int num) : num(num)
{
// No-op.
}
/**
* Copy constructor.
*
* @param other Other instance.
*/
CacheEntryModifier(const CacheEntryModifier& other) : num(other.num)
{
// No-op.
}
/**
* Assignment operator.
*
* @param other Other instance.
* @return This instance.
*/
CacheEntryModifier& operator=(const CacheEntryModifier& other)
{
num = other.num;
return *this;
}
/**
* Call instance.
*
* @return New value of entry multiplied by two.
*/
virtual int Process(MutableCacheEntry<int, int>& entry, const int& arg)
{
if (entry.IsExists())
entry.SetValue(entry.GetValue() - arg - num);
else
entry.SetValue(42);
return entry.GetValue() * 2;
}
/**
* Get number.
*
* @return Number to substract from entry value.
*/
int GetNum() const
{
return num;
}
private:
/** Number to substract. */
int num;
};
namespace ignite
{
namespace binary
{
/**
* Binary type definition for CacheEntryModifier.
*/
IGNITE_BINARY_TYPE_START(CacheEntryModifier)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(CacheEntryModifier)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(CacheEntryModifier)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
IGNITE_BINARY_IS_NULL_FALSE(CacheEntryModifier)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(CacheEntryModifier)
static void Write(BinaryWriter& writer, const CacheEntryModifier& obj)
{
writer.WriteInt32("num", obj.GetNum());
}
static void Read(BinaryReader& reader, CacheEntryModifier& dst)
{
int num = reader.ReadInt32("num");
dst = CacheEntryModifier(num);
}
IGNITE_BINARY_TYPE_END
}
}
/**
* Divisor class for invoke tests.
*/
class Divisor : public CacheEntryProcessor<int, int, double, double>
{
public:
/**
* Constructor.
*/
Divisor() : scale(1.0)
{
// No-op.
}
/**
* Constructor.
*
* @param scale Scale.
*/
Divisor(double scale) : scale(scale)
{
// No-op.
}
/**
* Copy constructor.
*
* @param other Other instance.
*/
Divisor(const Divisor& other) : scale(other.scale)
{
// No-op.
}
/**
* Assignment operator.
*
* @param other Other instance.
* @return This instance.
*/
Divisor& operator=(const Divisor& other)
{
scale = other.scale;
return *this;
}
/**
* Call instance.
*
* @return New value before cast to int.
*/
virtual double Process(MutableCacheEntry<int, int>& entry, const double& arg)
{
double res = 0.0;
if (entry.IsExists())
{
res = (entry.GetValue() / arg) * scale;
entry.SetValue(static_cast<int>(res));
}
return res;
}
/**
* Get scale.
*
* @return Scale.
*/
double GetScale() const
{
return scale;
}
private:
/** Scale. */
double scale;
};
namespace ignite
{
namespace binary
{
/**
* Binary type definition for Divisor.
*/
IGNITE_BINARY_TYPE_START(Divisor)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(Divisor)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(Divisor)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
IGNITE_BINARY_IS_NULL_FALSE(Divisor)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(Divisor)
static void Write(BinaryWriter& writer, const Divisor& obj)
{
writer.WriteDouble("scale", obj.GetScale());
}
static void Read(BinaryReader& reader, Divisor& dst)
{
double scale = reader.ReadDouble("scale");
dst = Divisor(scale);
}
IGNITE_BINARY_TYPE_END
}
}
/**
* Character remover class for invoke tests.
*/
class CharRemover : public CacheEntryProcessor<std::string, std::string, int, bool>
{
public:
/**
* Constructor.
*/
CharRemover() : toRemove(0)
{
// No-op.
}
/**
* Constructor.
*
* @param toRemove Char to remove.
*/
CharRemover(char toRemove) : toRemove(toRemove)
{
// No-op.
}
/**
* Copy constructor.
*
* @param other Other instance.
*/
CharRemover(const CharRemover& other) : toRemove(other.toRemove)
{
// No-op.
}
/**
* Assignment operator.
*
* @param other Other instance.
* @return This instance.
*/
CharRemover& operator=(const CharRemover& other)
{
toRemove = other.toRemove;
return *this;
}
/**
* Call instance.
*
* @return New value before cast to int.
*/
virtual int Process(MutableCacheEntry<std::string, std::string>& entry, const bool& replaceWithSpace)
{
int res = 0;
if (entry.IsExists())
{
std::string val(entry.GetValue());
res = static_cast<int>(std::count(val.begin(), val.end(), toRemove));
if (replaceWithSpace)
std::replace(val.begin(), val.end(), toRemove, ' ');
else
val.erase(std::remove(val.begin(), val.end(), toRemove), val.end());
if (val.empty())
entry.Remove();
else
entry.SetValue(val);
}
return res;
}
/**
* Get scale.
*
* @return Scale.
*/
char GetCharToRemove() const
{
return toRemove;
}
private:
/** Char to remove. */
char toRemove;
};
namespace ignite
{
namespace binary
{
/**
* Binary type definition for CharRemover.
*/
IGNITE_BINARY_TYPE_START(CharRemover)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(CharRemover)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(CharRemover)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
IGNITE_BINARY_IS_NULL_FALSE(CharRemover)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(CharRemover)
static void Write(BinaryWriter& writer, const CharRemover& obj)
{
writer.WriteInt8("toRemove", obj.GetCharToRemove());
}
static void Read(BinaryReader& reader, CharRemover& dst)
{
char toRemove = static_cast<char>(reader.ReadInt8("toRemove"));
dst = CharRemover(toRemove);
}
IGNITE_BINARY_TYPE_END
}
}
/**
* PlatformComputeBinarizable class representation for the Java class with the
* same name for invoke tests.
*/
struct PlatformComputeBinarizable
{
public:
/**
* Constructor.
*/
PlatformComputeBinarizable() : field(0)
{
// No-op.
}
/**
* Constructor.
*
* @param field Field.
*/
PlatformComputeBinarizable(int32_t field) : field(field)
{
// No-op.
}
/**
* Copy constructor.
*
* @param other Other instance.
*/
PlatformComputeBinarizable(const PlatformComputeBinarizable& other) : field(other.field)
{
// No-op.
}
/**
* Assignment operator.
*
* @param other Other instance.
* @return This instance.
*/
PlatformComputeBinarizable& operator=(const PlatformComputeBinarizable& other)
{
field = other.field;
return *this;
}
/** Field. */
int32_t field;
};
namespace ignite
{
namespace binary
{
/**
* Binary type definition for PlatformComputeBinarizable.
*/
IGNITE_BINARY_TYPE_START(PlatformComputeBinarizable)
IGNITE_BINARY_GET_TYPE_ID_AS_HASH(PlatformComputeBinarizable)
IGNITE_BINARY_GET_TYPE_NAME_AS_IS(PlatformComputeBinarizable)
IGNITE_BINARY_GET_FIELD_ID_AS_HASH
IGNITE_BINARY_IS_NULL_FALSE(PlatformComputeBinarizable)
IGNITE_BINARY_GET_NULL_DEFAULT_CTOR(PlatformComputeBinarizable)
static void Write(BinaryWriter& writer, const PlatformComputeBinarizable& obj)
{
writer.WriteInt32("field", obj.field);
}
static void Read(BinaryReader& reader, PlatformComputeBinarizable& dst)
{
dst.field = reader.ReadInt32("field");
}
IGNITE_BINARY_TYPE_END
}
}
IGNITE_EXPORTED_CALL void IgniteModuleInit(ignite::IgniteBindingContext& context)
{
IgniteBinding binding = context.GetBinding();
binding.RegisterCacheEntryProcessor<CacheEntryModifier>();
binding.RegisterCacheEntryProcessor<Divisor>();
}
/**
* Test setup fixture.
*/
struct CacheInvokeTestSuiteFixture
{
Ignite node;
/**
* Constructor.
*/
CacheInvokeTestSuiteFixture() :
#ifdef IGNITE_TESTS_32
node(ignite_test::StartNode("cache-query-32.xml", "InvokeTest"))
#else
node(ignite_test::StartNode("cache-query.xml", "InvokeTest"))
#endif
{
// No-op.
}
/**
* Destructor.
*/
~CacheInvokeTestSuiteFixture()
{
Ignition::StopAll(true);
}
};
BOOST_FIXTURE_TEST_SUITE(CacheInvokeTestSuite, CacheInvokeTestSuiteFixture)
/**
* Test cache invoke on existing entry.
*/
BOOST_AUTO_TEST_CASE(TestExisting)
{
Cache<int, int> cache = node.GetOrCreateCache<int, int>("TestCache");
cache.Put(5, 20);
CacheEntryModifier ced(5);
int res = cache.Invoke<int>(5, ced, 4);
BOOST_CHECK_EQUAL(res, 22);
BOOST_CHECK_EQUAL(cache.Get(5), 11);
}
/**
* Test cache invoke on non-existing entry.
*/
BOOST_AUTO_TEST_CASE(TestNonExisting)
{
Cache<int, int> cache = node.GetOrCreateCache<int, int>("TestCache");
CacheEntryModifier ced;
int res = cache.Invoke<int>(4, ced, 4);
BOOST_CHECK_EQUAL(res, 84);
BOOST_CHECK_EQUAL(cache.Get(4), 42);
}
/**
* Test cache several invokes on the same entry.
*/
BOOST_AUTO_TEST_CASE(TestSeveral)
{
Cache<int, int> cache = node.GetOrCreateCache<int, int>("TestCache");
CacheEntryModifier ced(2);
Divisor div(10.0);
int res1 = cache.Invoke<int>(100, ced, 0);
BOOST_CHECK_EQUAL(res1, 84);
BOOST_CHECK_EQUAL(cache.Get(100), 42);
double res2 = cache.Invoke<double>(100, div, 200.0);
BOOST_CHECK_CLOSE(res2, 2.1, 1E-6);
BOOST_CHECK_EQUAL(cache.Get(100), 2);
res2 = cache.Invoke<double>(100, div, 3.0);
BOOST_CHECK_CLOSE(res2, 6.6666666, 1E-6);
BOOST_CHECK_EQUAL(cache.Get(100), 6);
res1 = cache.Invoke<int>(100, ced, -12);
BOOST_CHECK_EQUAL(res1, 32);
BOOST_CHECK_EQUAL(cache.Get(100), 16);
}
/**
* Test cache several invokes on the string entry.
*/
BOOST_AUTO_TEST_CASE(TestStrings)
{
IgniteBinding binding = node.GetBinding();
binding.RegisterCacheEntryProcessor<CharRemover>();
Cache<std::string, std::string> cache = node.GetOrCreateCache<std::string, std::string>("TestCache");
CharRemover cr('.');
int res = cache.Invoke<int>("some key", cr, false);
BOOST_CHECK_EQUAL(res, 0);
BOOST_CHECK(!cache.ContainsKey("some key"));
cache.Put("some key", "Some.Value.Separated.By.Dots");
res = cache.Invoke<int>("some key", cr, false);
BOOST_CHECK_EQUAL(res, 4);
BOOST_CHECK_EQUAL(cache.Get("some key"), std::string("SomeValueSeparatedByDots"));
cache.Put("some key", "Some.Other.Weird.Value");
res = cache.Invoke<int>("some key", cr, true);
BOOST_CHECK_EQUAL(res, 3);
BOOST_CHECK_EQUAL(cache.Get("some key"), std::string("Some Other Weird Value"));
cache.Put("some key", "...........");
res = cache.Invoke<int>("some key", cr, false);
BOOST_CHECK_EQUAL(res, 11);
BOOST_CHECK(!cache.ContainsKey("some key"));
}
/**
* Test cache invoke of Java CacheEntryProcessor.
*/
BOOST_AUTO_TEST_CASE(TestJavaProcessor)
{
const static std::string procName = "org.apache.ignite.platform.PlatformAddArgEntryProcessor";
Cache<int64_t, int64_t> cache = node.GetOrCreateCache<int64_t, int64_t>("TestJavaProcessorCache");
cache.Put(5, 10);
int64_t res = cache.InvokeJava<int64_t, int64_t>(5, procName, 8);
BOOST_CHECK_EQUAL(res, 18);
BOOST_CHECK_EQUAL(cache.Get(5), 18);
res = cache.InvokeJava<int64_t, int64_t>(4, procName, 42);
BOOST_CHECK_EQUAL(res, 42);
BOOST_CHECK_EQUAL(cache.Get(4), 42);
}
/**
* Test cache invoke of Java CacheEntryProcessor binarizable.
*/
BOOST_AUTO_TEST_CASE(TestJavaProcessorBinarizable)
{
const static std::string procName = "org.apache.ignite.platform.PlatformAddArgEntryProcessorBinarizable";
Cache<int64_t, int64_t> cache = node.GetOrCreateCache<int64_t, int64_t>("TestJavaProcessorCacheBinarizable");
cache.Put(15, 40);
PlatformComputeBinarizable res = cache.InvokeJava<PlatformComputeBinarizable, int64_t>(15, procName, -12);
BOOST_CHECK_EQUAL(res.field, 28);
BOOST_CHECK_EQUAL(cache.Get(15), 28);
res = cache.InvokeJava<PlatformComputeBinarizable, int64_t>(4, procName, 42);
BOOST_CHECK_EQUAL(res.field, 42);
BOOST_CHECK_EQUAL(cache.Get(4), 42);
}
BOOST_AUTO_TEST_SUITE_END()