alephant 0.0.4-java → 0.0.5-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ac3689e07939593c100632167541ecc2efd0994a
4
- data.tar.gz: b12b4f8cd17d1a380eabdb1bf44f93ed62628fa0
3
+ metadata.gz: 2fab1ace0ff9d2ef8b5bb2003bb6fced04808a48
4
+ data.tar.gz: fd3b8c6a161ea075fef0865fbb1278cb5ac4c47c
5
5
  SHA512:
6
- metadata.gz: 2094d441612a43e1571817ece377e602f9367f33b7b91cadc003b33a20144cda6938f8f08c207970949efb6dfcd142a684d1bd0cea00ac92b821a65db4077876
7
- data.tar.gz: 054fcbe96e00401de0376192925c9278089b386238be2b3bb6c7a44b1085da372620ea1caf4bf081d2be98f142a8446d5d56380e3d7b2fffee46edb55cd8a168
6
+ metadata.gz: d72470cccb094e58d2735fbce0b19fbf2840949f2ba3aabfd97bd0c400fe8b43baf1da54577677d4c006d972ed49808eef25f9400f4c52641f4df5b05880a345
7
+ data.tar.gz: 35b38982cfc40c7cf796c2b440d288a6373b0e948f54d85e63e0f4ed8bb806dd9d7c8ea9e3971eb780579dda240b69d3f3fc55378daa42c0fe53df06b4d867a5
data/.gitignore CHANGED
@@ -4,4 +4,5 @@ Gemfile.lock
4
4
 
5
5
  /pkg
6
6
  /tmp
7
+ /views
7
8
 
data/.ruby-version CHANGED
@@ -1 +1 @@
1
- jruby-1.7.8
1
+ jruby-1.7.9
data/README.md CHANGED
@@ -3,16 +3,19 @@ alephant
3
3
 
4
4
  Static publishing to S3 on push notification from SQS
5
5
 
6
- [![Code Climate](https://codeclimate.com/repos/52cd866de30ba018f10000a2/badges/5d9c02131201565a630e/gpa.png)](https://codeclimate.com/repos/52cd866de30ba018f10000a2/feed)
6
+ [![Code Climate](https://codeclimate.com/repos/52d6bec56956802e26011a0f/badges/fce457795179641460e0/gpa.png)](https://codeclimate.com/repos/52d6bec56956802e26011a0f/feed)
7
7
 
8
- [![Build Status](https://travis-ci.org/kenoir/alephant.png?branch=master)](https://travis-ci.org/kenoir/alephant)
8
+ [![Build Status](https://travis-ci.org/BBC-News/alephant.png?branch=master)](https://travis-ci.org/BBC-News/alephant)
9
9
 
10
10
  [![Gem Version](https://badge.fury.io/rb/alephant.png)](http://badge.fury.io/rb/alephant)
11
11
 
12
12
  ##Dependencies
13
13
 
14
14
  - JRuby 1.7.8
15
- - An AWS account
15
+ - An AWS account (you'll need to create):
16
+ - An S3 bucket
17
+ - An SQS Queue
18
+ - A Dynamo DB table (optional, will attempt to create if can't be found)
16
19
 
17
20
  ##Setup
18
21
 
@@ -30,7 +33,64 @@ gem install alephant
30
33
  In your application:
31
34
  ```rb
32
35
  require 'alephant'
36
+ opts = {
37
+ :s3_bucket_id => 'bucket-id',
38
+ :s3_object_path => 'path/to/object',
39
+ :s3_object_id => 'object_id',
40
+ :table_name => 'your_dynamo_db_table',
41
+ :sqs_queue_id => 'https://your_amazon_sqs_queue_url',
42
+ :view_id => 'my_view_id',
43
+ :sequential_proc => Proc.new { |last_seen_id, data|
44
+ last_seen_id < data["sequence_id"].to_i
45
+ },
46
+ :set_last_seen_proc => Proc.new { |data|
47
+ data["sequence_id"].to_i
48
+ }
49
+ }
33
50
 
34
- Alephant.run('your_cache_id')
51
+ thread = Alephant::Alephant.new(opts).run!
52
+ thread.join
53
+ ```
54
+
55
+ Provide a view in a folder:
56
+
57
+ ```
58
+ └── views
59
+ ├── models
60
+ │   └── foo.rb
61
+ └── templates
62
+ └── foo.mustache
63
+ ```
64
+
65
+ **SQS Message Format**
66
+
67
+ ```json
68
+ {
69
+ "content": "hello world",
70
+ "sequential_id": 1
71
+ }
72
+ ```
73
+
74
+ **foo.rb**
75
+ ```rb
76
+ module MyApp
77
+ module Views
78
+ class Foo < Alephant::Views::Base
79
+ def content
80
+ @data['content']
81
+ end
82
+ end
83
+ end
84
+ end
85
+ ```
86
+
87
+ **foo.mustache**
88
+ ```mustache
89
+ {{content}}
90
+ ```
91
+
92
+ **S3 Output**
93
+ ```
94
+ hello world
35
95
  ```
36
96
 
data/lib/alephant.rb CHANGED
@@ -1,7 +1,11 @@
1
+ $: << File.dirname(__FILE__)
2
+
1
3
  require 'aws-sdk'
2
- require 'env'
3
4
  require 'json'
4
5
 
6
+ require_relative 'env'
7
+
8
+ require 'alephant/models/queue'
5
9
  require 'alephant/models/cache'
6
10
  require 'alephant/models/renderer'
7
11
  require 'alephant/models/sequencer'
@@ -9,31 +13,72 @@ require 'alephant/models/sequencer'
9
13
  require 'alephant/errors'
10
14
  require 'alephant/views'
11
15
 
12
-
13
16
  module Alephant
17
+ class Alephant
18
+ attr_reader :sequencer, :queue, :cache, :renderer
14
19
 
15
- def self.run(cache_id)
16
- queue = AWS::SQS.new.queues.create(cache_id)
17
- cache = Cache.new(cache_id)
18
- sequencer = Sequencer.new(cache_id)
19
- renderer = Renderer.new(cache_id)
20
+ VALID_OPTS = [
21
+ :s3_bucket_id,
22
+ :s3_object_path,
23
+ :s3_object_id,
24
+ :table_name,
25
+ :sqs_queue_id,
26
+ :view_id,
27
+ :sequential_proc,
28
+ :set_last_seen_proc
29
+ ]
20
30
 
21
- thread = Thread.new do
22
- puts "Polling queue..."
23
- queue.poll do |msg|
24
- data = JSON.parse(msg.body)
31
+ def initialize(opts = {})
32
+ set_opts(opts)
25
33
 
26
- if data["seq"] > sequencer.last_seen
27
- puts "Rendering from message #{data["seq"]}"
34
+ @sequencer = Sequencer.new(
35
+ {
36
+ :table_name => @table_name
37
+ },
38
+ @sqs_queue_id
39
+ )
40
+
41
+ @queue = Queue.new(@sqs_queue_id)
42
+ @cache = Cache.new(@s3_bucket_id, @s3_object_path)
43
+ @renderer = Renderer.new(@view_id)
44
+ end
45
+
46
+ def parse(msg)
47
+ JSON.parse(msg)
48
+ end
49
+
50
+ def write(data)
51
+ @cache.put(
52
+ @s3_object_id,
53
+ @renderer.render(data)
54
+ )
55
+ end
28
56
 
29
- content = renderer.render(data)
30
- cache.put(cache_id, content)
31
- sequencer.last_seen = data["seq"]
57
+ def receive(msg)
58
+ data = parse(msg.body)
59
+
60
+ if @sequencer.sequential?(data, &@sequential_proc)
61
+ write data
62
+ @sequencer.set_last_seen(data, &@set_last_seen_proc)
63
+ end
64
+ end
65
+
66
+ def run!
67
+ Thread.new do
68
+ @queue.poll { |msg| receive(msg) }
69
+ end
70
+ end
71
+
72
+ private
73
+ def set_opts(opts)
74
+ VALID_OPTS.each do | k |
75
+ v = opts.has_key?(k) ? opts[k] : nil
76
+ singleton_class.class_eval do
77
+ attr_accessor k
32
78
  end
79
+ send("#{k}=", v)
33
80
  end
34
81
  end
35
82
 
36
- thread
37
83
  end
38
84
  end
39
-
@@ -2,19 +2,23 @@ require 'aws-sdk'
2
2
 
3
3
  module Alephant
4
4
  class Cache
5
+ attr_reader :id, :bucket, :path
5
6
 
6
- def initialize(id)
7
- @s3_bucket = AWS::S3.new.buckets.create(id)
8
- end
7
+ def initialize(id, path)
8
+ @id = id
9
+ @path = path
9
10
 
10
- def get(object_id)
11
- @s3_bucket.objects[object_id].read
11
+ s3 = AWS::S3.new
12
+ @bucket = s3.buckets[id]
12
13
  end
13
14
 
14
- def put(object_id, data)
15
- @s3_bucket.objects[object_id].write(data)
15
+ def put(id, data)
16
+ @bucket.objects["#{@path}/#{id}"].write(data)
16
17
  end
17
18
 
19
+ def get(id)
20
+ @bucket.objects["#{@path}/#{id}"].read
21
+ end
18
22
  end
19
23
  end
20
24
 
@@ -0,0 +1,25 @@
1
+ require 'aws-sdk'
2
+
3
+ module Alephant
4
+ class Queue
5
+ attr_accessor :q
6
+
7
+ def initialize(id)
8
+ @sqs = AWS::SQS.new
9
+ @q = @sqs.queues[id]
10
+
11
+ unless @q.exists?
12
+ @q = @sqs.queues.create(id)
13
+ sleep_until_queue_exists
14
+ end
15
+ end
16
+
17
+ def sleep_until_queue_exists
18
+ sleep 1 until @q.exists?
19
+ end
20
+
21
+ def poll(*args, &block)
22
+ @q.poll(*args, &block)
23
+ end
24
+ end
25
+ end
@@ -2,40 +2,64 @@ require 'aws-sdk'
2
2
 
3
3
  module Alephant
4
4
  class Sequencer
5
- attr_reader :id, :table
5
+ attr_reader :id, :table_name, :table_conf
6
6
 
7
- def initialize(id)
8
- @id = id
9
-
10
- dynamo_db = AWS::DynamoDB.new
11
- schema = {
12
- :hash_key => {
13
- :key => :string,
14
- :value => :string
7
+ def table_conf_defaults
8
+ {
9
+ :write_units => 5,
10
+ :read_units => 10,
11
+ :schema => {
12
+ :hash_key => {
13
+ :key => :string,
14
+ :value => :string
15
+ }
15
16
  }
16
17
  }
18
+ end
19
+
20
+ def initialize(opts, id)
21
+ dynamo_db = AWS::DynamoDB.new
22
+
23
+ @id = id
24
+ @table_name = opts[:table_name]
25
+ @table_conf = opts[:table_conf] || table_conf_defaults
26
+ @table = dynamo_db.tables[@table_name]
17
27
 
18
- @table = dynamo_db.tables[id]
19
28
  begin
20
29
  sleep_until_table_active
21
30
  rescue AWS::DynamoDB::Errors::ResourceNotFoundException
22
- puts "CREATING TABLE: #{id}"
23
- @table = dynamo_db.tables.create(id, 10, 5, schema)
31
+ @table = dynamo_db.tables.create(
32
+ @table_name,
33
+ @table_conf[:read_units],
34
+ @table_conf[:write_units],
35
+ @table_conf[:schema]
36
+ )
24
37
 
25
38
  sleep_until_table_active
26
39
  end
40
+ end
27
41
 
42
+ def sequential?(data)
43
+ if block_given?
44
+ yield(get_last_seen, data)
45
+ else
46
+ get_last_seen < data["sequence_id"].to_i
47
+ end
28
48
  end
29
49
 
30
- def sequential?(n)
31
- last_seen < n
50
+ def set_last_seen(data)
51
+ last_seen_id = block_given? ? yield(data) : data["sequence_id"]
52
+
53
+ batch = AWS::DynamoDB::BatchWrite.new
54
+ batch.put(@table_name, [:key => @id,:value => last_seen_id])
55
+ batch.process!
32
56
  end
33
57
 
34
- def last_seen
58
+ def get_last_seen
35
59
  begin
36
60
  @table.batch_get(
37
61
  ['value'],
38
- ['last_seen'],
62
+ [@id],
39
63
  {
40
64
  :consistent_read => true
41
65
  }
@@ -45,13 +69,6 @@ module Alephant
45
69
  end
46
70
  end
47
71
 
48
- def last_seen=(last_seen)
49
- batch = AWS::DynamoDB::BatchWrite.new
50
- batch.put(@id, [:key => "last_seen",:value => last_seen])
51
- batch.process!
52
- end
53
-
54
- private
55
72
  def sleep_until_table_active
56
73
  sleep 1 until @table.status == :active
57
74
  end
@@ -1,3 +1,3 @@
1
1
  module Alephant
2
- VERSION = "0.0.4"
2
+ VERSION = "0.0.5"
3
3
  end
@@ -0,0 +1,193 @@
1
+ require 'spec_helper'
2
+
3
+ describe Alephant::Alephant do
4
+ subject { Alephant::Alephant }
5
+
6
+ describe "initialize(opts = {})" do
7
+ before(:each) do
8
+ sequencer = double()
9
+ queue = double()
10
+ cache = double()
11
+ renderer = double()
12
+
13
+ Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
14
+ Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
15
+ Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
16
+ Alephant::Renderer.any_instance.stub(:initialize).and_return(renderer)
17
+ end
18
+
19
+ it "sets specified options" do
20
+ instance = subject.new({
21
+ :s3_bucket_id => :s3_bucket_id,
22
+ :s3_object_path => :s3_object_path,
23
+ :s3_object_id => :s3_object_id,
24
+ :table_name => :table_name,
25
+ :sqs_queue_id => :sqs_queue_id,
26
+ :view_id => :view_id,
27
+ :sequential_proc => :sequential_proc,
28
+ :set_last_seen_proc => :set_last_seen_proc
29
+ })
30
+
31
+ expect(instance.s3_bucket_id).to eq(:s3_bucket_id);
32
+ expect(instance.s3_object_path).to eq(:s3_object_path);
33
+ expect(instance.s3_object_id).to eq(:s3_object_id);
34
+ expect(instance.table_name).to eq(:table_name);
35
+ expect(instance.sqs_queue_id).to eq(:sqs_queue_id);
36
+ expect(instance.view_id).to eq(:view_id);
37
+ expect(instance.sequential_proc).to eq(:sequential_proc);
38
+ expect(instance.set_last_seen_proc).to eq(:set_last_seen_proc);
39
+ end
40
+
41
+ it "sets unspecified options to nil" do
42
+ instance = subject.new
43
+
44
+ expect(instance.s3_bucket_id).to eq(nil);
45
+ expect(instance.s3_object_path).to eq(nil);
46
+ expect(instance.s3_object_id).to eq(nil);
47
+ expect(instance.table_name).to eq(nil);
48
+ expect(instance.sqs_queue_id).to eq(nil);
49
+ expect(instance.view_id).to eq(nil);
50
+ expect(instance.sequential_proc).to eq(nil);
51
+ expect(instance.set_last_seen_proc).to eq(nil);
52
+ end
53
+
54
+ context "initializes @sequencer" do
55
+ it "with Sequencer.new({ :table_name => :table_name }, @sqs_queue_id)" do
56
+ Alephant::Sequencer.should_receive(:new)
57
+ .with({ :table_name => :table_name }, :sqs_queue_id)
58
+
59
+ instance = subject.new({
60
+ :table_name => :table_name,
61
+ :sqs_queue_id => :sqs_queue_id
62
+ })
63
+ end
64
+ end
65
+
66
+ context "initializes @queue" do
67
+ it "with Queue.new(@sqs_queue_id)" do
68
+ Alephant::Queue.should_receive(:new).with(:sqs_queue_id)
69
+
70
+ instance = subject.new({
71
+ :sqs_queue_id => :sqs_queue_id
72
+ })
73
+ end
74
+ end
75
+
76
+ context "initializes @cache" do
77
+ it "with Cache.new(@s3_bucket_id, @s3_object_path)" do
78
+ Alephant::Cache.should_receive(:new).with(:s3_bucket_id, :s3_object_path)
79
+
80
+ instance = subject.new({
81
+ :s3_bucket_id => :s3_bucket_id,
82
+ :s3_object_path => :s3_object_path
83
+ })
84
+ end
85
+ end
86
+
87
+ context "initializes @renderer" do
88
+ it "with Renderer.new(@view_id)" do
89
+ Alephant::Renderer.should_receive(:new).with(:view_id)
90
+
91
+ instance = subject.new({
92
+ :view_id => :view_id
93
+ })
94
+ end
95
+ end
96
+ end
97
+
98
+ describe "run!" do
99
+ before(:each) do
100
+ sequencer = double()
101
+ queue = double()
102
+ cache = double()
103
+ renderer = double()
104
+
105
+ Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
106
+ Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
107
+ Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
108
+ Alephant::Renderer.any_instance.stub(:initialize).and_return(renderer)
109
+ end
110
+
111
+ it "returns a Thread" do
112
+ instance = subject.new({
113
+ :sqs_queue_id => :sqs_queue_id
114
+ })
115
+
116
+ expect(instance.run!).to be_a(Thread)
117
+ end
118
+
119
+ it "calls @queue.poll" do
120
+ instance = subject.new({
121
+ :sqs_queue_id => :sqs_queue_id
122
+ })
123
+
124
+ instance.should_receive(:receive).with(:msg)
125
+
126
+ expect_any_instance_of(Alephant::Queue).to receive(:poll).and_yield(:msg)
127
+
128
+ t = instance.run!
129
+ t.join
130
+ end
131
+ end
132
+
133
+ describe "receive(msg)" do
134
+ before(:each) do
135
+ sequencer = double()
136
+ queue = double()
137
+ cache = double()
138
+ renderer = double()
139
+
140
+ Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
141
+ Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
142
+ Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
143
+ Alephant::Renderer.any_instance.stub(:initialize).and_return(renderer)
144
+ end
145
+
146
+ it "takes json as an argument" do
147
+ instance = subject.new
148
+ msg = double()
149
+ msg.stub(:body).and_return('notjson')
150
+
151
+ expect { instance.receive(msg) }.to raise_error(JSON::ParserError);
152
+ end
153
+
154
+ it "writes data to cache if sequential order is true" do
155
+ data = "{ \"foo\":\"bar\" }"
156
+ msg = double()
157
+ msg.stub(:body).and_return(data)
158
+
159
+ instance = subject.new
160
+
161
+ Alephant::Sequencer.any_instance.stub(:sequential?).and_return(true)
162
+ Alephant::Sequencer.any_instance.stub(:set_last_seen)
163
+
164
+ instance.should_receive(:write).with(JSON.parse(data))
165
+ instance.receive(msg)
166
+ end
167
+ end
168
+
169
+ describe "write(data)" do
170
+ before(:each) do
171
+ sequencer = double()
172
+ queue = double()
173
+ cache = double()
174
+ renderer = double()
175
+
176
+ Alephant::Sequencer.any_instance.stub(:initialize).and_return(sequencer)
177
+ Alephant::Queue.any_instance.stub(:initialize).and_return(queue)
178
+ Alephant::Cache.any_instance.stub(:initialize).and_return(cache)
179
+ Alephant::Renderer.any_instance.stub(:initialize).and_return(renderer)
180
+ end
181
+
182
+ it "puts rendered data into the S3 Cache" do
183
+ Alephant::Cache.any_instance.should_receive(:put).with(:s3_object_id, :content)
184
+ Alephant::Renderer.any_instance.stub(:render).and_return(:content)
185
+
186
+ instance = subject.new({
187
+ :s3_object_id => :s3_object_id
188
+ })
189
+
190
+ instance.write(:content)
191
+ end
192
+ end
193
+ end
@@ -0,0 +1,63 @@
1
+ require 'spec_helper'
2
+ require 'pry'
3
+
4
+ describe Alephant::Cache do
5
+ let(:id) { :id }
6
+ let(:path) { :path }
7
+ let(:data) { :data }
8
+ subject { Alephant::Cache }
9
+
10
+ describe "initialize(id, path)" do
11
+ it "sets and exposes id, path instance variables " do
12
+ instance = subject.new(id, path)
13
+ expect(instance.id).to eq(id)
14
+ expect(instance.path).to eq(path)
15
+ end
16
+
17
+ it "sets bucket instance variable as S3 bucket with id" do
18
+ instance = subject.new(id, path)
19
+
20
+ expect(instance.bucket).to be_an AWS::S3::Bucket
21
+ expect(instance.bucket.name).to eq('id')
22
+ end
23
+ end
24
+
25
+ describe "put(id, data)" do
26
+ it "sets bucket path/id content data" do
27
+ s3_object_collection = double()
28
+ s3_object_collection.should_receive(:write).with(:data)
29
+
30
+ s3_bucket = double()
31
+ s3_bucket.should_receive(:objects).and_return(
32
+ {
33
+ "path/id" => s3_object_collection
34
+ }
35
+ )
36
+
37
+ AWS::S3.any_instance.stub(:buckets).and_return({ id => s3_bucket })
38
+ instance = subject.new(id, path)
39
+
40
+ instance.put(id, data);
41
+ end
42
+ end
43
+
44
+ describe "get(id)" do
45
+ it "gets bucket path/id content data" do
46
+ s3_object_collection = double()
47
+ s3_object_collection.should_receive(:read)
48
+
49
+ s3_bucket = double()
50
+ s3_bucket.should_receive(:objects).and_return(
51
+ {
52
+ "path/id" => s3_object_collection
53
+ }
54
+ )
55
+
56
+ AWS::S3.any_instance.stub(:buckets).and_return({ id => s3_bucket })
57
+
58
+ instance = subject.new(id, path)
59
+ instance.get(id);
60
+ end
61
+ end
62
+ end
63
+
@@ -0,0 +1,78 @@
1
+ require 'spec_helper'
2
+
3
+ describe Alephant::Queue do
4
+ subject { Alephant::Queue }
5
+
6
+ describe "initialize(id)" do
7
+ it "sets @q to an instance of AWS:SQS::Queue" do
8
+ AWS::SQS::Queue.any_instance.stub(:exists?)
9
+ .and_return(true)
10
+
11
+ instance = subject.new(:id)
12
+ expect(instance.q).to be_a(AWS::SQS::Queue)
13
+ end
14
+
15
+ context "@q.exists? == false" do
16
+ it "@q = AWS::SQS.new.queues.create(id), then sleep_until_queue_exists" do
17
+ queue = double()
18
+ queue.stub(:exists?).and_return(false)
19
+
20
+ queue_collection = double()
21
+ queue_collection.should_receive(:create).with(:id)
22
+ .and_return(queue)
23
+
24
+ sqs = double()
25
+ sqs.should_receive(:queues)
26
+ .and_return({ :id => queue }, queue_collection)
27
+
28
+ AWS::SQS.should_receive(:new).and_return(sqs)
29
+
30
+ subject.any_instance.should_receive(:sleep_until_queue_exists)
31
+
32
+ instance = subject.new(:id)
33
+ end
34
+ end
35
+ end
36
+
37
+ describe "poll(*args, &block)" do
38
+ it "calls @q.poll(*args, &block)" do
39
+ block = double()
40
+ block.should_receive(:called)
41
+
42
+ AWS::SQS::Queue.any_instance.stub(:exists?)
43
+ .and_return(true)
44
+
45
+ AWS::SQS::Queue.any_instance.should_receive(:poll).with(:arg).and_yield
46
+
47
+ subject.new(:id).poll(:arg) do
48
+ block.called
49
+ end
50
+ end
51
+ end
52
+
53
+ describe "sleep_until_queue_exists" do
54
+ context "@q.exists? == true" do
55
+ it "should not call sleep" do
56
+ AWS::SQS::Queue.any_instance.stub(:exists?)
57
+ .and_return(true)
58
+
59
+ Alephant::Queue.any_instance.stub(:sleep)
60
+ Alephant::Queue.any_instance.should_not_receive(:sleep)
61
+
62
+ subject.new(:id).sleep_until_queue_exists
63
+ end
64
+ end
65
+ context "@q.exists? == false" do
66
+ it "should call sleep(1)" do
67
+ AWS::SQS::Queue.any_instance.stub(:exists?)
68
+ .and_return(true, false, true)
69
+
70
+ Alephant::Queue.any_instance.stub(:sleep)
71
+ Alephant::Queue.any_instance.should_receive(:sleep).with(1)
72
+
73
+ subject.new(:id).sleep_until_queue_exists
74
+ end
75
+ end
76
+ end
77
+
78
+ end
@@ -0,0 +1,121 @@
1
+ require 'spec_helper'
2
+
3
+ describe Alephant::Sequencer do
4
+ subject { Alephant::Sequencer }
5
+
6
+ describe "initialize(opts, id)" do
7
+
8
+ it "sets @id, @table_name and @table_conf" do
9
+ AWS::DynamoDB.any_instance.stub(:initialize).and_return({
10
+ :tables => {
11
+ :status => :active
12
+ }
13
+ })
14
+
15
+ Alephant::Sequencer.any_instance.stub(:sleep_until_table_active)
16
+
17
+ instance = subject.new({
18
+ :table_name => :table_name,
19
+ :table_conf => :table_conf
20
+ }, :sqs_queue_id)
21
+
22
+ expect(instance.id).to eq(:sqs_queue_id)
23
+ expect(instance.table_name).to eq(:table_name)
24
+ expect(instance.table_conf).to eq(:table_conf)
25
+ end
26
+
27
+ context "sleep_until_table_active raises" do
28
+ context "AWS::DynamoDB::Errors::ResourceNotFoundException" do
29
+ it "dynamo_db.tables.create(@table_name, opts) then sleep_until_table_active" do
30
+ opts = {
31
+ :table_name => :table_name,
32
+ :table_conf => {
33
+ :read_units => :read_units,
34
+ :write_units => :write_units,
35
+ :schema => :schema
36
+ }
37
+ }
38
+
39
+ table_collection = double()
40
+ table_collection.should_receive(:create).with(
41
+ opts[:table_name],
42
+ opts[:table_conf][:read_units],
43
+ opts[:table_conf][:write_units],
44
+ opts[:table_conf][:schema]
45
+ )
46
+
47
+ AWS::DynamoDB.any_instance.stub(:tables).and_return({},table_collection)
48
+
49
+ Alephant::Sequencer
50
+ .any_instance
51
+ .stub(:sleep_until_table_active).and_yield do
52
+ @times_called ||= 0
53
+ raise AWS::DynamoDB::Errors::ResourceNotFoundException if @times_called == 0
54
+ @times_called += 1
55
+ end
56
+
57
+ subject.new(opts, :id)
58
+ end
59
+ end
60
+ end
61
+ end
62
+
63
+ describe "sequential?(data)" do
64
+ before(:each) do
65
+ Alephant::Sequencer
66
+ .any_instance.stub(:initialize)
67
+ .and_return(double())
68
+ end
69
+
70
+ context "block_given? == true" do
71
+ it "yields to block" do
72
+ Alephant::Sequencer
73
+ .any_instance
74
+ .stub(:get_last_seen)
75
+ .and_return(1)
76
+
77
+ instance = subject.new
78
+
79
+ in_sequence = instance.sequential?(:data) do |last_seen, data|
80
+ :foo
81
+ end
82
+
83
+ expect(in_sequence).to eq(:foo)
84
+ end
85
+ end
86
+
87
+ context "block_given? == false" do
88
+ context "get_last_seen < data['sequence_id']" do
89
+ it "returns true" do
90
+ Alephant::Sequencer
91
+ .any_instance
92
+ .stub(:get_last_seen)
93
+ .and_return(0)
94
+
95
+ instance = subject.new
96
+
97
+ data = { "sequence_id" => "1" }
98
+
99
+ expect(instance.sequential? data).to be(true)
100
+ end
101
+ end
102
+
103
+ context "get_last_seen >= data['sequence_id']" do
104
+ it "returns false" do
105
+ Alephant::Sequencer
106
+ .any_instance
107
+ .stub(:get_last_seen)
108
+ .and_return(1)
109
+
110
+ instance = subject.new
111
+
112
+ data = { "sequence_id" => "0" }
113
+
114
+ expect(instance.sequential? data).to be(false)
115
+ end
116
+ end
117
+ end
118
+
119
+ end
120
+ end
121
+
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  $: << File.join(File.dirname(__FILE__),"..", "lib")
2
2
 
3
+ require 'pry'
3
4
  require 'alephant'
4
5
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: alephant
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.4
4
+ version: 0.0.5
5
5
  platform: java
6
6
  authors:
7
7
  - Robert Kenny
@@ -143,6 +143,7 @@ files:
143
143
  - lib/alephant/errors/view_model_not_found.rb
144
144
  - lib/alephant/errors/view_template_not_found.rb
145
145
  - lib/alephant/models/cache.rb
146
+ - lib/alephant/models/queue.rb
146
147
  - lib/alephant/models/renderer.rb
147
148
  - lib/alephant/models/sequencer.rb
148
149
  - lib/alephant/util/string.rb
@@ -150,9 +151,13 @@ files:
150
151
  - lib/alephant/views.rb
151
152
  - lib/alephant/views/base.rb
152
153
  - lib/env.rb
154
+ - spec/alephant_spec.rb
155
+ - spec/cache_spec.rb
153
156
  - spec/fixtures/views/models/example.rb
154
157
  - spec/fixtures/views/templates/example.mustache
158
+ - spec/queue_spec.rb
155
159
  - spec/renderer_spec.rb
160
+ - spec/sequencer_spec.rb
156
161
  - spec/spec_helper.rb
157
162
  homepage: http://rubygems.org/gems/alephant
158
163
  licenses:
@@ -179,7 +184,11 @@ signing_key:
179
184
  specification_version: 4
180
185
  summary: Static Publishing in the Cloud
181
186
  test_files:
187
+ - spec/alephant_spec.rb
188
+ - spec/cache_spec.rb
182
189
  - spec/fixtures/views/models/example.rb
183
190
  - spec/fixtures/views/templates/example.mustache
191
+ - spec/queue_spec.rb
184
192
  - spec/renderer_spec.rb
193
+ - spec/sequencer_spec.rb
185
194
  - spec/spec_helper.rb