alephant 0.0.4-java → 0.0.5-java

Sign up to get free protection for your applications and to get access to all the features.
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