From 637827f10e33a260e0e7766193a1d64057a4f1a8 Mon Sep 17 00:00:00 2001 From: Jurriaan Pruis Date: Thu, 5 Jan 2012 14:57:29 +0100 Subject: [PATCH] Added API --- lib/fnordmetric.rb | 1 + lib/fnordmetric/api.rb | 37 +++++++++++ lib/fnordmetric/inbound_stream.rb | 27 ++------ spec/api_spec.rb | 107 ++++++++++++++++++++++++++++++ 4 files changed, 150 insertions(+), 22 deletions(-) create mode 100644 lib/fnordmetric/api.rb create mode 100644 spec/api_spec.rb diff --git a/lib/fnordmetric.rb b/lib/fnordmetric.rb index 1b31cb650..79858a8b4 100644 --- a/lib/fnordmetric.rb +++ b/lib/fnordmetric.rb @@ -123,6 +123,7 @@ def self.standalone end +require "fnordmetric/api" require "fnordmetric/inbound_stream" require "fnordmetric/worker" require "fnordmetric/widget" diff --git a/lib/fnordmetric/api.rb b/lib/fnordmetric/api.rb new file mode 100644 index 000000000..28e7906e0 --- /dev/null +++ b/lib/fnordmetric/api.rb @@ -0,0 +1,37 @@ +require 'securerandom' +class FnordMetric::API + @@opts = nil + def initialize opts + @@opts = FnordMetric.default_options opts + connect + end + + def connect + @redis = @@opts[:redis] if @@opts[:redis] + @redis = Redis.connect(:url => @@opts[:redis_url]) + end + + def event event_data + push_event get_next_uuid, event_data + end + + def disconnect + @redis.quit + end + + private + + def push_event(event_id, event_data) + prefix = @@opts[:redis_prefix] + @redis.hincrby "#{prefix}-testdata", "events_received", 1 + @redis.hincrby "#{prefix}-stats", "events_received", 1 + @redis.set "#{prefix}-event-#{event_id}", event_data + @redis.lpush "#{prefix}-queue", event_id + @redis.expire "#{prefix}-event-#{event_id}", @@opts[:event_queue_ttl] + event_id + end + + def get_next_uuid + SecureRandom.uuid + end +end \ No newline at end of file diff --git a/lib/fnordmetric/inbound_stream.rb b/lib/fnordmetric/inbound_stream.rb index ba02a41b6..c164ecad1 100644 --- a/lib/fnordmetric/inbound_stream.rb +++ b/lib/fnordmetric/inbound_stream.rb @@ -1,6 +1,4 @@ -require 'securerandom' class FnordMetric::InboundStream < EventMachine::Connection - @@opts = nil def self.start(opts) @@ -13,18 +11,6 @@ def receive_data(chunk) EM.defer{ next_event } end - def push_event(event_id, event_data) - prefix = @@opts[:redis_prefix] - - @redis.hincrby "#{prefix}-stats", "events_received", 1 - @redis.set "#{prefix}-event-#{event_id}", event_data - @redis.lpush "#{prefix}-queue", event_id - @redis.expire "#{prefix}-event-#{event_id}", @@opts[:event_queue_ttl] - - @events_buffered -= 1 - close_connection? - end - def next_event read_next_event push_next_event @@ -39,20 +25,18 @@ def read_next_event def push_next_event return true if @events.empty? - push_event(get_next_uuid, @events.pop) + @api.event event_data + @events_buffered -= 1 + close_connection? EM.next_tick(&method(:push_next_event)) end - def get_next_uuid - SecureRandom.uuid - end - def close_connection? - @redis.quit unless @streaming || (@events_buffered!=0) + @api.disconnect unless @streaming || (@events_buffered!=0) end def post_init - @redis = Redis.connect(:url => @@opts[:redis_url]) + @api = API.new(@@opts) @events_buffered = 0 @streaming = true @buffer = "" @@ -63,5 +47,4 @@ def unbind @streaming = false close_connection? end - end diff --git a/spec/api_spec.rb b/spec/api_spec.rb new file mode 100644 index 000000000..ad2564bc8 --- /dev/null +++ b/spec/api_spec.rb @@ -0,0 +1,107 @@ +require ::File.expand_path('../spec_helper.rb', __FILE__) + +describe FnordMetric::Event do + + include FnordMetric + + before(:all) do + @now = Time.utc(1992,01,13,5,23,23).to_i + @redis = Redis.new + @redis_wrap = RedisWrap.new(@redis) + + @namespace = "fnordmetric-test-ns1234-api" + @timeline = "#{@namespace}-timeline" + + @opts = { + :namespace_prefix => "#{@namespace}", + :redis_prefix => "fnordmetric-test", + :redis => @redis + } + @api = API.new @opts + end + + describe "finding events using API" do + + before(:each) do + @redis.keys("fnordmetric-test-*").each { |k| @redis.del(k) } + end + + it "should find all events" do + create_event({:_type => "foo", :_time => @now}) + create_event({:_type => "foo", :_time => @now}) + Event.all(@opts).length.should == 2 + end + + it "should find all events and return event objects" do + create_event({:_type => "foo", :_time => @now}) + Event.all(@opts).first.should be_a(FnordMetric::Event) + end + + it "should find all events and returnevent objects with time" do + create_event({:_type => "Fn0rd", :blah => :blubb, :_time => @now}) + events = Event.all(@opts) + events.first.time.to_i.should == @now + end + + it "should find an event and return a event object" do + event_id = create_event({:_type => "Fn0rd", :_time => @now}) + event = Event.find(event_id, @opts) + event.should be_a(FnordMetric::Event) + event.type.should == "Fn0rd" + end + + it "should find an event and return a event object with data" do + event_id = create_event({:_type => "Fn0rd", :blah => :blubb, :_time => @now}) + event = Event.find(event_id, @opts) + event.data(:blah).should == "blubb" + end + + it "should find an event and return a event object with id" do + event_id = create_event({:_type => "Fn0rd", :blah => :blubb, :_time => @now}) + event = Event.find(event_id, @opts) + event.id.should == event_id + end + + it "should find all in the correct order" do + create_event({:_type => "foo", :_time => @now-17}) + create_event({:_type => "foo", :_time => @now-23}) + create_event({:_type => "foo", :_time => @now-42}) + create_event({:_type => "foo", :_time => @now-5}) + Event.all(@opts).length.should == 4 + end + + it "should find all events since a given time, including that exact time" do + create_event({:_type => "foo", :_time => @now-42}) + create_event({:_type => "foo", :_time => @now-23}) + create_event({:_type => "foo", :_time => @now-17}) + create_event({:_type => "foo", :_time => @now-5}) + Event.all(@opts).length.should == 4 + Event.all(@opts.merge(:since => @now-42)).length.should == 4 + Event.all(@opts.merge(:since => @now-23)).length.should == 3 + Event.all(@opts.merge(:since => @now-22)).length.should == 2 + Event.all(@opts.merge(:since => @now-17)).length.should == 2 + Event.all(@opts.merge(:since => @now-16)).length.should == 1 + Event.all(@opts.merge(:since => @now-5)).length.should == 1 + end + + it "should find a maximum number of events" do + create_event( {:_type => "foo", :_time => @now-42}) + create_event( {:_type => "foo", :_time => @now-23}) + create_event( {:_type => "foo", :_time => @now-17}) + create_event( {:_type => "foo", :_time => @now-5}) + Event.all(@opts).length.should == 4 + Event.all(@opts.merge(:limit => 2)).length.should == 2 + end + + + + def create_event(event_data) + event_id = @api.event event_data.to_json + @redis_wrap.zadd(@timeline, event_data.delete(:_time), event_id) + event_id + end + + end + + +end