From 8103bff7570289289550feceb2ca45eab836d20a Mon Sep 17 00:00:00 2001 From: Armin Date: Fri, 25 May 2018 13:36:44 +0200 Subject: [PATCH] JAVAFICATION: Port RubyTimestamp test to JUnit Fixes #9661 --- logstash-core/spec/logstash/timestamp_spec.rb | 45 ---------- .../ext/JrubyTimestampExtLibrary.java | 24 ++--- .../ext/JrubyTimestampExtLibraryTest.java | 89 +++++++++++++++++++ 3 files changed, 101 insertions(+), 57 deletions(-) delete mode 100644 logstash-core/spec/logstash/timestamp_spec.rb create mode 100644 logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java diff --git a/logstash-core/spec/logstash/timestamp_spec.rb b/logstash-core/spec/logstash/timestamp_spec.rb deleted file mode 100644 index ea9d7a7e1..000000000 --- a/logstash-core/spec/logstash/timestamp_spec.rb +++ /dev/null @@ -1,45 +0,0 @@ -# encoding: utf-8 - -require "spec_helper" - -describe LogStash::Timestamp do - context "constructors" do - # Via JRuby 9k time see logstash/issues/7463 - # JRuby 9k now uses Java 8 Time with nanosecond precision but - # our Timestamp use Joda with millisecond precision - # expected: 2017-06-15 10:34:08.389999999 +0000 - # got: 2017-06-15 10:34:08.389000000 +0000 - # we may need to use `be_within(0.000999999).of()` in other places too - it "should work" do - t = LogStash::Timestamp.new - expect(t.time.to_i).to be_within(2).of Time.now.to_i - - t = LogStash::Timestamp.now - expect(t.time.to_i).to be_within(2).of Time.now.to_i - - now = DateTime.now.to_time.utc - t = LogStash::Timestamp.new(now) - expect(t.time.to_f).to be_within(0.000999999).of(now.to_f) - - t = LogStash::Timestamp.at(now.to_i) - expect(t.time.to_i).to eq(now.to_i) - end - - it "should have consistent behaviour across == and .eql?" do - its_xmas = Time.utc(2015, 12, 25, 0, 0, 0) - expect(LogStash::Timestamp.new(its_xmas)).to eql(LogStash::Timestamp.new(its_xmas)) - expect(LogStash::Timestamp.new(its_xmas)).to be ==(LogStash::Timestamp.new(its_xmas)) - end - - it "should raise exception on invalid format" do - expect{LogStash::Timestamp.new("foobar")}.to raise_error - end - - it "compares to any type" do - t = LogStash::Timestamp.new - expect(t == '-').to be_falsey - end - - end - -end diff --git a/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java b/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java index 6f4a866b2..a8b6cb5f9 100644 --- a/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java +++ b/logstash-core/src/main/java/org/logstash/ext/JrubyTimestampExtLibrary.java @@ -49,31 +49,31 @@ public final class JrubyTimestampExtLibrary { } // def initialize(time = Time.new) - @JRubyMethod(name = "initialize", optional = 1) - public IRubyObject ruby_initialize(ThreadContext context, IRubyObject[] args) - { + @JRubyMethod(optional = 1) + public JrubyTimestampExtLibrary.RubyTimestamp initialize(final ThreadContext context, + IRubyObject[] args) { args = Arity.scanArgs(context.runtime, args, 0, 1); IRubyObject time = args[0]; if (time.isNil()) { this.timestamp = new Timestamp(); } else if (time instanceof RubyTime) { - this.timestamp = new Timestamp(((RubyTime)time).getDateTime()); + this.timestamp = new Timestamp(((RubyTime) time).getDateTime()); } else if (time instanceof RubyString) { try { this.timestamp = new Timestamp(time.toString()); } catch (IllegalArgumentException e) { throw new RaiseException( - getRuntime(), RubyUtil.TIMESTAMP_PARSER_ERROR, - "invalid timestamp string format " + time, - true + getRuntime(), RubyUtil.TIMESTAMP_PARSER_ERROR, + "invalid timestamp string format " + time, + true ); } } else { throw context.runtime.newTypeError("wrong argument type " + time.getMetaClass() + " (expected Time)"); } - return context.nil; + return this; } @JRubyMethod(name = "time") @@ -180,8 +180,8 @@ public final class JrubyTimestampExtLibrary { } @JRubyMethod(name = "at", required = 1, optional = 1, meta = true) - public static IRubyObject ruby_at(ThreadContext context, IRubyObject recv, IRubyObject[] args) - { + public static JrubyTimestampExtLibrary.RubyTimestamp ruby_at(ThreadContext context, + IRubyObject recv, IRubyObject[] args) { RubyTime t; if (args.length == 1) { // JRuby 9K has fixed the problem iwth BigDecimal precision see https://github.com/elastic/logstash/issues/4565 @@ -193,8 +193,8 @@ public final class JrubyTimestampExtLibrary { } @JRubyMethod(name = "now", meta = true) - public static IRubyObject ruby_now(ThreadContext context, IRubyObject recv) - { + public static JrubyTimestampExtLibrary.RubyTimestamp ruby_now(ThreadContext context, + IRubyObject recv) { return RubyTimestamp.newRubyTimestamp(context.runtime, new Timestamp()); } diff --git a/logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java b/logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java new file mode 100644 index 000000000..c3fb68a4b --- /dev/null +++ b/logstash-core/src/test/java/org/logstash/ext/JrubyTimestampExtLibraryTest.java @@ -0,0 +1,89 @@ +package org.logstash.ext; + +import java.util.concurrent.TimeUnit; +import org.assertj.core.api.Assertions; +import org.jruby.exceptions.RaiseException; +import org.jruby.runtime.ThreadContext; +import org.jruby.runtime.builtin.IRubyObject; +import org.junit.Test; +import org.logstash.RubyUtil; + +/** + * Tests for {@link JrubyTimestampExtLibrary}. + */ +public final class JrubyTimestampExtLibraryTest { + + @Test + public void testConstructorNew() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + final JrubyTimestampExtLibrary.RubyTimestamp t = + newRubyTimestamp(context, new IRubyObject[0]); + final long now = + TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + Assertions.assertThat(t.ruby_time(context).to_i().getLongValue()) + .isBetween(now - 1L, now + 2L); + } + + @Test + public void testConstructorNow() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + final JrubyTimestampExtLibrary.RubyTimestamp t = + JrubyTimestampExtLibrary.RubyTimestamp.ruby_now(context, RubyUtil.RUBY_TIMESTAMP_CLASS); + final long now = + TimeUnit.SECONDS.convert(System.currentTimeMillis(), TimeUnit.MILLISECONDS); + Assertions.assertThat(t.ruby_time(context).to_i().getLongValue()) + .isBetween(now - 1L, now + 2L); + } + + @Test + public void testConstructFromRubyDateTime() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + final IRubyObject now = + context.runtime.evalScriptlet("require 'date'\nDateTime.now.to_time.utc"); + final JrubyTimestampExtLibrary.RubyTimestamp t = + newRubyTimestamp(context, new IRubyObject[]{now}); + Assertions.assertThat( + Math.abs( + t.ruby_time(context).to_f().getDoubleValue() - now.convertToFloat().getDoubleValue() + ) + ).isLessThan(0.000999999); + final IRubyObject nowToI = now.callMethod(context, "to_i"); + Assertions.assertThat(JrubyTimestampExtLibrary.RubyTimestamp.ruby_at( + context, RubyUtil.RUBY_TIMESTAMP_CLASS, new IRubyObject[]{nowToI} + ).ruby_to_i(context)).isEqualTo(nowToI); + } + + @Test + public void testConsistentEql() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + final IRubyObject[] itsXmas = + {context.runtime.evalScriptlet("Time.utc(2015, 12, 25, 0, 0, 0)")}; + final IRubyObject left = newRubyTimestamp(context, itsXmas); + final IRubyObject right = newRubyTimestamp(context, itsXmas); + Assertions.assertThat(left.callMethod(context, "eql?", right).isTrue()).isTrue(); + Assertions.assertThat(left.callMethod(context, "==", right).isTrue()).isTrue(); + } + + @Test(expected = RaiseException.class) + public void testRaiseOnInvalidFormat() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + newRubyTimestamp(context, new IRubyObject[]{context.runtime.newString("foobar")}); + } + + @Test + public void testCompareAnyType() { + final ThreadContext context = RubyUtil.RUBY.getCurrentContext(); + Assertions.assertThat( + newRubyTimestamp(context, new IRubyObject[0]).eql( + context, context.runtime.newString("-") + ).isTrue() + ).isFalse(); + } + + private static JrubyTimestampExtLibrary.RubyTimestamp newRubyTimestamp( + final ThreadContext context, final IRubyObject[] args) { + return new JrubyTimestampExtLibrary.RubyTimestamp( + context.runtime, RubyUtil.RUBY_TIMESTAMP_CLASS + ).initialize(context, args); + } +}