blob: d67e4eb861de477cb3f67b94cec62aa909a3a5aa [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 <stdint.h>
#include <sstream>
#include <gtest/gtest.h>
#include <mesos/values.hpp>
#include <stout/gtest.hpp>
#include <stout/interval.hpp>
#include <stout/try.hpp>
#include "common/values.hpp"
#include "master/master.hpp"
using namespace mesos::internal::values;
namespace mesos {
extern void coalesce(Value::Ranges* ranges);
extern void coalesce(Value::Ranges* ranges, const Value::Range& range);
} // namespace mesos {
namespace mesos {
namespace internal {
namespace tests {
TEST(ValuesTest, ValidInput)
{
// Test parsing scalar type.
Try<Value> result1 = parse("45.55");
ASSERT_SOME(result1);
ASSERT_EQ(Value::SCALAR, result1->type());
EXPECT_DOUBLE_EQ(45.55, result1->scalar().value());
// Test parsing ranges type.
Try<Value> result2 = parse("[10000-20000, 30000-50000]");
ASSERT_SOME(result2);
ASSERT_EQ(Value::RANGES, result2->type());
EXPECT_EQ(2, result2->ranges().range_size());
EXPECT_EQ(10000u, result2->ranges().range(0).begin());
EXPECT_EQ(20000u, result2->ranges().range(0).end());
EXPECT_EQ(30000u, result2->ranges().range(1).begin());
EXPECT_EQ(50000u, result2->ranges().range(1).end());
// Test parsing set type.
Try<Value> result3 = parse("{sda1, sda2}");
ASSERT_SOME(result3);
ASSERT_EQ(Value::SET, result3->type());
ASSERT_EQ(2, result3->set().item_size());
EXPECT_EQ("sda1", result3->set().item(0));
EXPECT_EQ("sda2", result3->set().item(1));
// Test parsing text type.
Try<Value> result4 = parse("123abc,s");
ASSERT_SOME(result4);
ASSERT_EQ(Value::TEXT, result4->type());
ASSERT_EQ("123abc,s", result4->text().value());
}
TEST(ValuesTest, InvalidInput)
{
// Test when '{' doesn't match.
EXPECT_ERROR(parse("{aa,b}}"));
// Test when '[' doesn't match.
EXPECT_ERROR(parse("[1-2]]"));
// Test when range is not numeric.
EXPECT_ERROR(parse("[1-2b]"));
// Test when giving empty string.
EXPECT_ERROR(parse(" "));
EXPECT_ERROR(parse("nan"));
EXPECT_ERROR(parse("-nan"));
EXPECT_ERROR(parse("inf"));
EXPECT_ERROR(parse("-inf"));
EXPECT_ERROR(parse("infinity"));
EXPECT_ERROR(parse("-infinity"));
}
TEST(ValuesTest, SetSubtraction)
{
Value::Set set1 = parse("{sda1, sda2, sda3}")->set();
Value::Set set2 = parse("{sda2, sda3}")->set();
Value::Set set3 = parse("{sda4}")->set();
set1 -= set2;
EXPECT_EQ(set1, parse("{sda1}")->set());
set3 -= set1;
EXPECT_EQ(set3, parse("{sda4}")->set());
}
// Test a simple range parse.
TEST(ValuesTest, RangesParse)
{
Value::Ranges ranges;
Value::Range* range = ranges.add_range();
range->set_begin(1);
range->set_end(10);
Value::Ranges parsed =
parse("[1-10]")->ranges();
EXPECT_EQ(ranges, parsed);
}
// Unit test coalescing given ranges.
TEST(ValuesTest, RangesCoalesce)
{
// Multiple overlap with explicit coalesce.
// Explicitly construct [1-4, 3-5, 7-8, 8-10].
Value::Ranges ranges;
Value::Range* range = ranges.add_range();
range->set_begin(1);
range->set_end(4);
range = ranges.add_range();
range->set_begin(3);
range->set_end(5);
range = ranges.add_range();
range->set_begin(7);
range->set_end(8);
range = ranges.add_range();
range->set_begin(8);
range->set_end(10);
mesos::coalesce(&ranges);
// Should be [1-5, 7-10].
ASSERT_EQ(2, ranges.range_size());
EXPECT_EQ(1U, ranges.range(0).begin());
EXPECT_EQ(5U, ranges.range(0).end());
EXPECT_EQ(7U, ranges.range(1).begin());
EXPECT_EQ(10U, ranges.range(1).end());
}
// Test coalescing given ranges via parse.
// Note: As the == operator triggers coalesce as well, we should
// check ranges_size() explicitly.
TEST(ValuesTest, RangesCoalesceParse)
{
// Test multiple ranges against explicitly constructed.
Value::Ranges ranges;
Value::Range* range = ranges.add_range();
range->set_begin(1);
range->set_end(10);
Value::Ranges parsed =
parse("[4-6, 6-8, 5-9, 3-4, 2-5, 4-6, 1-1, 10-10, 4-6]")->ranges();
EXPECT_EQ(ranges, parsed);
EXPECT_EQ(1, parsed.range_size());
// Simple overlap.
parsed = parse("[4-6, 6-8]")->ranges();
Value::Ranges expected = parse("[4-8]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
// Simple overlap unordered.
parsed = parse("[6-8, 4-6]")->ranges();
expected = parse("[4-8]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
// Subsumed range.
parsed = parse("[1-10, 8-10]")->ranges();
expected = parse("[1-10]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
// Completely subsumed.
parsed = parse("[1-11, 8-10]")->ranges();
expected = parse("[1-11]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
// Multiple overlapping ranges.
parsed = parse("[1-4, 4-5, 7-8, 8-10]")->ranges();
expected = parse("[1-5, 7-10]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(2, parsed.range_size());
// Multiple overlap mixed.
parsed = parse("[7-8, 1-4, [8-10], 4-5]")->ranges();
expected = parse("[1-5, 7-10]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(2, parsed.range_size());
// Simple neighboring with overlap.
parsed = parse("[4-6, 7-8]")->ranges();
expected = parse("[4-8]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
// Single neighbouring.
parsed = parse("[4-6, 7-7]")->ranges();
expected = parse("[4-7]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
// Multiple ranges coalescing into a single one.
parsed = parse("[4-6, 7-7, 8-8, 9-9]")->ranges();
expected = parse("[4-9]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
// Multiple ranges coalescing into multiple ranges.
parsed = parse("[4-6, 7-7, 9-10, 9-11]")->ranges();
expected = parse("[4-7, 9-11]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(2, parsed.range_size());
// Multiple duplicates.
parsed = parse("[6-8, 6-8, 4-6, 6-8]")->ranges();
expected = parse("[4-8]")->ranges();
EXPECT_EQ(parsed, expected);
EXPECT_EQ(1, parsed.range_size());
}
// Test adding a new range to an existing coalesced range.
// Note: As the == operator triggers coalesce as well, we should
// check ranges_size() explicitly.
TEST(ValuesTest, AddRangeCoalesce)
{
// Multiple overlap with explicit coalesce.
// Explicitly construct [1-4, 8-10].
Value::Ranges ranges;
Value::Range* range = ranges.add_range();
range->set_begin(1);
range->set_end(4);
range = ranges.add_range();
range->set_begin(8);
range->set_end(10);
// Range [4-8].
Value::Range range2;
range2.set_begin(4);
range2.set_end(8);
mesos::coalesce(&ranges, range2);
// Should be coalesced to [1-10].
ASSERT_EQ(1, ranges.range_size());
EXPECT_EQ(1U, ranges.range(0).begin());
EXPECT_EQ(10U, ranges.range(0).end());
// Multiple neighboring with explicit coalesce.
// Range [5-7].
range2.set_begin(5);
range2.set_end(7);
mesos::coalesce(&ranges, range2);
// Should be coalesced to [1-10].
ASSERT_EQ(1, ranges.range_size());
EXPECT_EQ(1U, ranges.range(0).begin());
EXPECT_EQ(10U, ranges.range(0).end());
// Completely subsumed.
// Range [5-7] (as before).
range2.set_begin(5);
range2.set_end(7);
mesos::coalesce(&ranges, range2);
// Should be coalesced to [1-10].
ASSERT_EQ(1, ranges.range_size());
EXPECT_EQ(1U, ranges.range(0).begin());
EXPECT_EQ(10U, ranges.range(0).end());
// None overlapping.
// Range [5-7] (as before).
range2.set_begin(20);
range2.set_end(21);
mesos::coalesce(&ranges, range2);
// Should be coalesced to [1-10, 20-21].
ASSERT_EQ(2, ranges.range_size());
EXPECT_EQ(1U, ranges.range(0).begin());
EXPECT_EQ(10U, ranges.range(0).end());
EXPECT_EQ(20U, ranges.range(1).begin());
EXPECT_EQ(21U, ranges.range(1).end());
}
// Test converting Ranges to IntervalSet.
TEST(ValuesTest, RangesToIntervalSet)
{
Value::Ranges ranges;
IntervalSet<uint64_t> set;
IntervalSet<uint64_t>::iterator interval;
// Initialize Ranges value as [1-1, 3-5, 7-8].
Value::Range* range = ranges.add_range();
range->set_begin(1);
range->set_end(1);
range = ranges.add_range();
range->set_begin(3);
range->set_end(5);
range = ranges.add_range();
range->set_begin(7);
range->set_end(8);
// Convert Ranges value to IntervalSet value.
set = rangesToIntervalSet<uint64_t>(ranges).get();
// Verify converting result which should be {[1,2), [3-6), [7-9)}.
ASSERT_EQ(3U, set.intervalCount());
interval = set.begin();
EXPECT_EQ(1U, interval->lower());
EXPECT_EQ(2U, interval->upper());
interval++;
EXPECT_EQ(3U, interval->lower());
EXPECT_EQ(6U, interval->upper());
interval++;
EXPECT_EQ(7U, interval->lower());
EXPECT_EQ(9U, interval->upper());
interval++;
EXPECT_EQ(set.end(), interval);
}
// Test converting IntervalSet to Ranges.
TEST(ValuesTest, IntervalSetToRanges)
{
Value::Ranges ranges;
IntervalSet<uint64_t> set;
// Initialize IntervalSet value as {[1-1], [3-4], [7-9]}.
set += (Bound<uint64_t>::closed(1), Bound<uint64_t>::closed(1));
set += (Bound<uint64_t>::closed(3), Bound<uint64_t>::closed(4));
set += (Bound<uint64_t>::closed(7), Bound<uint64_t>::closed(9));
// Convert IntervalSet value to Ranges value.
ranges = intervalSetToRanges(set);
// Verify converting result which should be [1-1, 3-4, 7-9].
ASSERT_EQ(3, ranges.range_size());
EXPECT_EQ(1U, ranges.range(0).begin());
EXPECT_EQ(1U, ranges.range(0).end());
EXPECT_EQ(3U, ranges.range(1).begin());
EXPECT_EQ(4U, ranges.range(1).end());
EXPECT_EQ(7U, ranges.range(2).begin());
EXPECT_EQ(9U, ranges.range(2).end());
}
// Test adding two ranges.
TEST(ValuesTest, RangesAddition)
{
// Overlaps on right.
Value::Ranges ranges1 = parse("[3-8]")->ranges();
Value::Ranges ranges2 = parse("[4-10]")->ranges();
EXPECT_EQ(parse("[3-10]")->ranges(), ranges1 + ranges2);
// Overlapps on right.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[1-4]")->ranges();
EXPECT_EQ(parse("[1-8]")->ranges(), ranges1 + ranges2);
// Completely subsumed.
ranges1 = parse("[2-3]")->ranges();
ranges2 = parse("[1-4]")->ranges();
EXPECT_EQ(parse("[1-4]")->ranges(), ranges1 + ranges2);
// Neighbouring right.
ranges1 = parse("[2-3]")->ranges();
ranges2 = parse("[4-6]")->ranges();
EXPECT_EQ(parse("[2-6]")->ranges(), ranges1 + ranges2);
// Neighbouring left.
ranges1 = parse("[3-5]")->ranges();
ranges2 = parse("[1-2]")->ranges();
EXPECT_EQ(parse("[1-5]")->ranges(), ranges1 + ranges2);
// Fills gap.
ranges1 = parse("[3-5, 7-8]")->ranges();
ranges2 = parse("[6-6]")->ranges();
EXPECT_EQ(parse("[3-8]")->ranges(), ranges1 + ranges2);
// Fills double gap.
ranges1 = parse("[1-4, 9-10, 20-22, 26-30]")->ranges();
ranges2 = parse("[5-8, 23-25]")->ranges();
EXPECT_EQ(parse("[1-10, 20-30]")->ranges(), ranges1 + ranges2);
}
// Test subtracting two ranges.
TEST(ValuesTest, RangesSubtraction)
{
// Ranges1 is empty.
Value::Ranges ranges1 = parse("[]")->ranges();
Value::Ranges ranges2 = parse("[1-10]")->ranges();
EXPECT_EQ(parse("[]")->ranges(), ranges1 - ranges2);
// Ranges2 is empty.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[]")->ranges();
EXPECT_EQ(parse("[3-8]")->ranges(), ranges1 - ranges2);
// Completely subsumes.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[1-10]")->ranges();
EXPECT_EQ(parse("[]")->ranges(), ranges1 - ranges2);
// Subsummed on left.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[3-5]")->ranges();
EXPECT_EQ(parse("[6-8]")->ranges(), ranges1 - ranges2);
// Subsummed on right.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[5-8]")->ranges();
EXPECT_EQ(parse("[3-4]")->ranges(), ranges1 - ranges2);
// Subsummed in the middle.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[5-6]")->ranges();
EXPECT_EQ(parse("[3-4, 7-8]")->ranges(), ranges1 - ranges2);
// Overlaps to the left.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[1-3]")->ranges();
EXPECT_EQ(parse("[4-8]")->ranges(), ranges1 - ranges2);
// Overlaps to the right.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[5-10]")->ranges();
EXPECT_EQ(parse("[3-4]")->ranges(), ranges1 - ranges2);
// Doesn't overlap right.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[9-10]")->ranges();
EXPECT_EQ(parse("[3-8]")->ranges(), ranges1 - ranges2);
// Doesn't overlap left.
ranges1 = parse("[3-8]")->ranges();
ranges2 = parse("[1-2]")->ranges();
EXPECT_EQ(parse("[3-8]")->ranges(), ranges1 - ranges2);
}
} // namespace tests {
} // namespace internal {
} // namespace mesos {