pyper_rb 1.2.0
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 +7 -0
- data/.gitignore +16 -0
- data/Gemfile +24 -0
- data/LICENSE.txt +22 -0
- data/README.md +178 -0
- data/Rakefile +10 -0
- data/lib/pyper/all.rb +4 -0
- data/lib/pyper/pipeline.rb +63 -0
- data/lib/pyper/pipes/cassandra/all_items_reader.rb +40 -0
- data/lib/pyper/pipes/cassandra/deleter.rb +19 -0
- data/lib/pyper/pipes/cassandra/mod_key.rb +32 -0
- data/lib/pyper/pipes/cassandra/mod_key_reader.rb +41 -0
- data/lib/pyper/pipes/cassandra/pagination_decoding.rb +22 -0
- data/lib/pyper/pipes/cassandra/pagination_encoding.rb +17 -0
- data/lib/pyper/pipes/cassandra/reader.rb +35 -0
- data/lib/pyper/pipes/cassandra/writer.rb +24 -0
- data/lib/pyper/pipes/cassandra.rb +8 -0
- data/lib/pyper/pipes/content/fetch.rb +30 -0
- data/lib/pyper/pipes/content/store.rb +36 -0
- data/lib/pyper/pipes/content.rb +2 -0
- data/lib/pyper/pipes/default_values.rb +15 -0
- data/lib/pyper/pipes/field_rename.rb +23 -0
- data/lib/pyper/pipes/force_enumerator.rb +13 -0
- data/lib/pyper/pipes/model/attribute_deserializer.rb +27 -0
- data/lib/pyper/pipes/model/attribute_serializer.rb +34 -0
- data/lib/pyper/pipes/model/attribute_validation.rb +57 -0
- data/lib/pyper/pipes/model/virtus_deserializer.rb +39 -0
- data/lib/pyper/pipes/model/virtus_parser.rb +13 -0
- data/lib/pyper/pipes/model.rb +5 -0
- data/lib/pyper/pipes/no_op.rb +15 -0
- data/lib/pyper/pipes/pry.rb +9 -0
- data/lib/pyper/pipes/remove_fields.rb +22 -0
- data/lib/pyper/pipes.rb +8 -0
- data/lib/pyper/version.rb +3 -0
- data/lib/pyper.rb +4 -0
- data/pyper_rb.gemspec +22 -0
- data/test/fixtures/cass_schema_config.yml +6 -0
- data/test/fixtures/test_datastore/schema.cql +23 -0
- data/test/test_helper.rb +34 -0
- data/test/unit/pyper/pipeline_test.rb +81 -0
- data/test/unit/pyper/pipes/cassandra/all_items_reader_test.rb +47 -0
- data/test/unit/pyper/pipes/cassandra/deleter_test.rb +37 -0
- data/test/unit/pyper/pipes/cassandra/mod_key_reader_test.rb +47 -0
- data/test/unit/pyper/pipes/cassandra/pagination_decoding_test.rb +29 -0
- data/test/unit/pyper/pipes/cassandra/pagination_encoding_test.rb +29 -0
- data/test/unit/pyper/pipes/cassandra/reader_test.rb +79 -0
- data/test/unit/pyper/pipes/cassandra/writer_test.rb +51 -0
- data/test/unit/pyper/pipes/content/fetch_test.rb +38 -0
- data/test/unit/pyper/pipes/content/store_test.rb +49 -0
- data/test/unit/pyper/pipes/field_rename_test.rb +24 -0
- data/test/unit/pyper/pipes/model/attribute_deserializer_test.rb +69 -0
- data/test/unit/pyper/pipes/model/attribute_serializer_test.rb +60 -0
- data/test/unit/pyper/pipes/model/attribute_validation_test.rb +96 -0
- data/test/unit/pyper/pipes/model/virtus_deserializer_test.rb +75 -0
- data/test/unit/pyper/pipes/no_op_test.rb +12 -0
- data/test/unit/pyper/pipes/remove_fields_test.rb +24 -0
- metadata +147 -0
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes::Cassandra
|
4
|
+
class ReaderTest < Minitest::Should::TestCase
|
5
|
+
context 'a cassandra reader pipe' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
setup_cass_schema
|
9
|
+
|
10
|
+
@client = create_cass_client('test_datastore')
|
11
|
+
@pipe = Reader.new(:test, @client)
|
12
|
+
|
13
|
+
# populate some test data
|
14
|
+
@client.insert(:test, {id: 'id', a: '1', b: 'b'})
|
15
|
+
@client.insert(:test, {id: 'id', a: '2', b: 'b'})
|
16
|
+
end
|
17
|
+
|
18
|
+
teardown do
|
19
|
+
teardown_cass_schema
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'read items from the cassandra table' do
|
23
|
+
out = @pipe.pipe(id: 'id').to_a
|
24
|
+
assert_equal 2, out.count
|
25
|
+
assert_equal({ "id" => "id", "a" => "1", "b" => "b" }, out.first)
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'return items in ascending order' do
|
29
|
+
out = @pipe.pipe(id: 'id').to_a
|
30
|
+
assert_equal %w(1 2), out.map { |i| i['a'] }
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'limit results if limit arg provided' do
|
34
|
+
out = @pipe.pipe(id: 'id', :limit => 1).to_a
|
35
|
+
assert_equal 1, out.count
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'order results by field and direction if order pair provided' do
|
39
|
+
out = @pipe.pipe(id: 'id', :order => [:a, :desc]).to_a
|
40
|
+
assert_equal %w(2 1), out.map { |i| i['a'] }
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'save page state and last_page in status' do
|
44
|
+
status = {}
|
45
|
+
out = @pipe.pipe({id: 'id', :page_size => 1}, status).to_a
|
46
|
+
assert_equal 1, out.count
|
47
|
+
assert_equal '1', out.first['a']
|
48
|
+
assert status[:paging_state]
|
49
|
+
assert_equal false, status[:last_page]
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'page through results if :page_size and/or :paging_state provided' do
|
53
|
+
status = {}
|
54
|
+
out = @pipe.pipe({id: 'id', :page_size => 1}, status).to_a
|
55
|
+
assert_equal 1, out.count
|
56
|
+
assert_equal '1', out.first['a']
|
57
|
+
paging_state = status[:paging_state]
|
58
|
+
|
59
|
+
out = @pipe.pipe({id: 'id', :page_size => 1, :paging_state => paging_state}, status).to_a
|
60
|
+
assert_equal 1, out.count
|
61
|
+
assert_equal '2', out.first['a']
|
62
|
+
assert_equal false, status[:last_page]
|
63
|
+
end
|
64
|
+
|
65
|
+
context "columns selecting" do
|
66
|
+
should "only select given columns from columns argument" do
|
67
|
+
out = @pipe.pipe({id: 'id', :columns => [:a]}).to_a
|
68
|
+
assert_equal({'a' => '1'}, out.first)
|
69
|
+
assert_equal({'a' => '2'}, out.last)
|
70
|
+
end
|
71
|
+
|
72
|
+
should "select all columns when columns argument not given" do
|
73
|
+
out = @pipe.pipe({id: 'id'}).to_a
|
74
|
+
assert_equal({ "id" => "id", "a" => "1", "b" => "b" }, out.first)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes::Cassandra
|
4
|
+
class WriterTest < Minitest::Should::TestCase
|
5
|
+
context 'a cassandra writer pipe' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
setup_cass_schema
|
9
|
+
|
10
|
+
@client = create_cass_client('test_datastore')
|
11
|
+
@writer = Writer.new(:test, @client)
|
12
|
+
end
|
13
|
+
|
14
|
+
teardown do
|
15
|
+
teardown_cass_schema
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'write to the specified cassandra table' do
|
19
|
+
attributes = {id: 'id', a: 'a', b: 'b'}
|
20
|
+
@writer.pipe(attributes)
|
21
|
+
row = @client.select(:test).execute.first
|
22
|
+
|
23
|
+
attributes.keys.each do |key|
|
24
|
+
assert_equal attributes[key], row[key.to_s]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
should 'raise an error if required attributes are not provided' do
|
29
|
+
attributes = {a: 'a', b: 'b'}
|
30
|
+
assert_raises(Cassandra::Errors::InvalidError) { @writer.pipe(attributes) }
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'return the original attributes if the write succeeds' do
|
34
|
+
attributes = {id: 'id', a: 'a', b: 'b'}
|
35
|
+
assert_equal attributes, @writer.pipe(attributes)
|
36
|
+
end
|
37
|
+
|
38
|
+
should 'raise an error if too many attributes are provided' do
|
39
|
+
attributes = {id: 'id', a: 'a', b: 'b', not_an_attribute: 'x'}
|
40
|
+
assert_raises(Cassandra::Errors::InvalidError) { @writer.pipe(attributes) }
|
41
|
+
end
|
42
|
+
|
43
|
+
should 'filter attributes if a filter set is given, returning the original attributes' do
|
44
|
+
attributes = {id: 'id', a: 'a', b: 'b', not_an_attribute: 'x'}
|
45
|
+
filter = [:id, :a, :b]
|
46
|
+
writer = Writer.new(:test, @client, filter)
|
47
|
+
assert_equal attributes, writer.pipe(attributes)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes::Content
|
4
|
+
class FetchTest < Minitest::Should::TestCase
|
5
|
+
context 'the content fetch pipe' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@dir = Dir.mktmpdir
|
9
|
+
@storage_builder = lambda do |item|
|
10
|
+
StorageStrategy.get("#{@dir}/content",
|
11
|
+
filters: [:size, :checksum],
|
12
|
+
size: { metadata_key: :raw_size },
|
13
|
+
checksum: {
|
14
|
+
digest: :sha256,
|
15
|
+
hash_type: :hex,
|
16
|
+
metadata_key: :raw_sha256
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
@pipe = Fetch.new(:content, &@storage_builder)
|
21
|
+
@strategy = @storage_builder.call({})
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'fetch content using the provided storage builder' do
|
25
|
+
content = 'asdf'
|
26
|
+
@strategy.write(content)
|
27
|
+
|
28
|
+
attributes = @pipe.pipe([{}])
|
29
|
+
assert_equal content, attributes.first[:content]
|
30
|
+
end
|
31
|
+
|
32
|
+
should 'add nothing if there is no content to store' do
|
33
|
+
attributes = @pipe.pipe([{}])
|
34
|
+
refute @content, attributes.first[:content]
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes::Content
|
4
|
+
class StoreTest < Minitest::Should::TestCase
|
5
|
+
context 'the content storage pipe' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@dir = Dir.mktmpdir
|
9
|
+
@storage_builder = lambda do |attributes|
|
10
|
+
StorageStrategy.get("#{@dir}/metadata",
|
11
|
+
filters: [:size, :checksum],
|
12
|
+
size: { metadata_key: :raw_size },
|
13
|
+
checksum: {
|
14
|
+
digest: :sha256,
|
15
|
+
hash_type: :hex,
|
16
|
+
metadata_key: :raw_sha256
|
17
|
+
})
|
18
|
+
end
|
19
|
+
|
20
|
+
@pipe = Store.new(:content, &@storage_builder)
|
21
|
+
@strategy = @storage_builder.call({})
|
22
|
+
end
|
23
|
+
|
24
|
+
should 'store content using the provided storage builder' do
|
25
|
+
content = 'asdf'
|
26
|
+
@pipe.pipe(:content => content)
|
27
|
+
|
28
|
+
assert_equal content, @strategy.read
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
should 'store size and checksum metadata' do
|
33
|
+
content = 'asdf'
|
34
|
+
@pipe.pipe(:content => content)
|
35
|
+
|
36
|
+
assert_equal '4', @strategy.metadata[:raw_size]
|
37
|
+
assert @strategy.metadata[:raw_sha256]
|
38
|
+
end
|
39
|
+
|
40
|
+
should 'remove content from attributes adding new metadata fields' do
|
41
|
+
content = 'asdf'
|
42
|
+
attributes = @pipe.pipe(:content => content)
|
43
|
+
|
44
|
+
assert_equal '4', attributes[:raw_size]
|
45
|
+
assert attributes[:raw_sha256]
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes
|
4
|
+
class FieldRenameTest < Minitest::Should::TestCase
|
5
|
+
context 'the field rename pipe' do
|
6
|
+
|
7
|
+
setup do
|
8
|
+
@pipe = FieldRename.new(:a => :b, "c" => "d")
|
9
|
+
end
|
10
|
+
|
11
|
+
should 'rename provided symbols as symbols' do
|
12
|
+
assert_equal({ :b => 1, :d => 1}, @pipe.pipe(:a => 1, :c => 1))
|
13
|
+
end
|
14
|
+
|
15
|
+
should 'rename provided strings as strings' do
|
16
|
+
assert_equal({ "b" => 1, "d" => 1}, @pipe.pipe("a" => 1, "c" => 1))
|
17
|
+
end
|
18
|
+
|
19
|
+
should 'rename nil values' do
|
20
|
+
assert_equal({ :b => nil, "d" => nil}, @pipe.pipe(:a => nil, "c" => nil))
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,69 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Pyper::Pipes::Model
|
5
|
+
class AttributeDeserializerTest < Minitest::Should::TestCase
|
6
|
+
setup do
|
7
|
+
type_mapping = {
|
8
|
+
:array => Array,
|
9
|
+
:hash => Hash,
|
10
|
+
:int => Integer,
|
11
|
+
:float => Float,
|
12
|
+
:other => String
|
13
|
+
}
|
14
|
+
@pipe = AttributeDeserializer.new(type_mapping)
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'deserialize json arrays' do
|
18
|
+
value = [1,2,3]
|
19
|
+
item = { :array => JSON.generate(value) }
|
20
|
+
out = @pipe.pipe([item])
|
21
|
+
assert_equal 1, out.count
|
22
|
+
assert_equal value, out.first[:array]
|
23
|
+
end
|
24
|
+
|
25
|
+
should 'deserialize json hashes' do
|
26
|
+
value = {'a' => 1}
|
27
|
+
item = { :hash => JSON.generate(value) }
|
28
|
+
out = @pipe.pipe([item])
|
29
|
+
assert_equal 1, out.count
|
30
|
+
assert_equal value, out.first[:hash]
|
31
|
+
end
|
32
|
+
|
33
|
+
should 'deserialize ints' do
|
34
|
+
value = 1
|
35
|
+
item = { :int => value.to_s }
|
36
|
+
out = @pipe.pipe([item])
|
37
|
+
assert_equal 1, out.count
|
38
|
+
assert_equal value, out.first[:int]
|
39
|
+
end
|
40
|
+
|
41
|
+
should 'deserialize fixnums' do
|
42
|
+
value = 1.5
|
43
|
+
item = { :float => value.to_s }
|
44
|
+
out = @pipe.pipe([item])
|
45
|
+
assert_equal 1, out.count
|
46
|
+
assert_equal value, out.first[:float]
|
47
|
+
end
|
48
|
+
|
49
|
+
should 'not deserialize other fields' do
|
50
|
+
value = 'asdf'
|
51
|
+
item = { :other => value }
|
52
|
+
out = @pipe.pipe([item])
|
53
|
+
assert_equal 1, out.count
|
54
|
+
assert_equal value, out.first[:other]
|
55
|
+
end
|
56
|
+
|
57
|
+
should 'not modify original values when deserializng' do
|
58
|
+
value = [1,2,3]
|
59
|
+
item = { :array => JSON.generate(value) }
|
60
|
+
out = @pipe.pipe([item])
|
61
|
+
assert_equal 1, out.count
|
62
|
+
assert_equal value, out.first[:array]
|
63
|
+
|
64
|
+
# This throws an error if we have modified the original values
|
65
|
+
out = @pipe.pipe([item])
|
66
|
+
assert_equal value, out.first[:array]
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'json'
|
3
|
+
|
4
|
+
module Pyper::Pipes::Model
|
5
|
+
class AttributeSerializerTest < Minitest::Should::TestCase
|
6
|
+
setup do
|
7
|
+
@pipe = AttributeSerializer.new
|
8
|
+
end
|
9
|
+
|
10
|
+
should 'serialize arrays to JSON' do
|
11
|
+
value = [1,2,3]
|
12
|
+
attributes = { :array => value }
|
13
|
+
out = @pipe.pipe(attributes)
|
14
|
+
assert_equal 1, out.count
|
15
|
+
assert_equal JSON.generate(value), out[:array]
|
16
|
+
end
|
17
|
+
|
18
|
+
should 'serialize hashes to JSON' do
|
19
|
+
value = {'a' => 1}
|
20
|
+
attributes = { :hash => value }
|
21
|
+
out = @pipe.pipe(attributes)
|
22
|
+
assert_equal 1, out.count
|
23
|
+
assert_equal JSON.generate(value), out[:hash]
|
24
|
+
end
|
25
|
+
|
26
|
+
should 'serialize datetimes to times' do
|
27
|
+
value = DateTime.now
|
28
|
+
attributes = { :datetime => value }
|
29
|
+
out = @pipe.pipe(attributes)
|
30
|
+
assert_equal 1, out.count
|
31
|
+
assert_equal value.to_time, out[:datetime]
|
32
|
+
end
|
33
|
+
|
34
|
+
should 'encode strings to utf-8' do
|
35
|
+
value = 'str'.force_encoding('ascii-8bit')
|
36
|
+
attributes = { :string => value }
|
37
|
+
out = @pipe.pipe(attributes)
|
38
|
+
assert_equal 1, out.count
|
39
|
+
assert_equal Encoding::UTF_8, out[:string].encoding
|
40
|
+
end
|
41
|
+
|
42
|
+
should 'be able to serialize collections containing strings with non-UTF8 characters to JSON' do
|
43
|
+
ascii = "\xC2\xA0".force_encoding('ascii-8bit')
|
44
|
+
time = DateTime.now
|
45
|
+
ascii_values = { :array => [ascii], :datetime => time, :fixnum => 1, :string => ascii }
|
46
|
+
utf8_values = { :array => [ascii.force_encoding("UTF-8")], :datetime => time, :fixnum => 1, :string => ascii.force_encoding("UTF-8") }
|
47
|
+
out = @pipe.pipe({ :hash => ascii_values })
|
48
|
+
assert_equal 1, out.count
|
49
|
+
assert_equal JSON.generate(utf8_values), out[:hash]
|
50
|
+
end
|
51
|
+
|
52
|
+
should 'not serialize other fields' do
|
53
|
+
value = 1.5
|
54
|
+
attributes = { :fixnum => value }
|
55
|
+
out = @pipe.pipe(attributes)
|
56
|
+
assert_equal 1, out.count
|
57
|
+
assert_equal value, out[:fixnum]
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,96 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes::Model
|
4
|
+
class AttributeValidationTest < Minitest::Should::TestCase
|
5
|
+
context "pipe" do
|
6
|
+
context "with required attributes" do
|
7
|
+
setup do
|
8
|
+
@opts = { :required => [:foo, :bar] }
|
9
|
+
@pipe = AttributeValidation.new(@opts)
|
10
|
+
end
|
11
|
+
|
12
|
+
should "raise when missing required attribute" do
|
13
|
+
error_1 = assert_raises(AttributeValidation::Failure) do
|
14
|
+
@pipe.pipe({})
|
15
|
+
end
|
16
|
+
assert_equal "Missing required attribute foo.", error_1.message
|
17
|
+
|
18
|
+
error_2 = assert_raises(AttributeValidation::Failure) do
|
19
|
+
@pipe.pipe({ :foo => "bar" })
|
20
|
+
end
|
21
|
+
assert_equal "Missing required attribute bar.", error_2.message
|
22
|
+
|
23
|
+
# Nothing should be raised now.
|
24
|
+
@pipe.pipe({ :foo => "bar", :bar => "qux" })
|
25
|
+
end
|
26
|
+
|
27
|
+
should "raise when required attribute is nil" do
|
28
|
+
error = assert_raises(AttributeValidation::Failure) do
|
29
|
+
@pipe.pipe({ :foo => nil, :bar => "qux"})
|
30
|
+
end
|
31
|
+
assert_equal "Missing required attribute foo.", error.message
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
context "with allowed attributes" do
|
36
|
+
setup do
|
37
|
+
@opts = { :allowed => [:foo, :bar] }
|
38
|
+
@pipe = AttributeValidation.new(@opts)
|
39
|
+
end
|
40
|
+
|
41
|
+
should "raise when attribute is not included in the whitelist" do
|
42
|
+
error = assert_raises(AttributeValidation::Failure) do
|
43
|
+
@pipe.pipe({ :foo => "foo", :bar => "bar", :baz => "baz" })
|
44
|
+
end
|
45
|
+
assert_equal "Attribute baz is not allowed.", error.message
|
46
|
+
|
47
|
+
# Nothing should be raised now.
|
48
|
+
@pipe.pipe({ :foo => "foo", :bar => "bar" })
|
49
|
+
end
|
50
|
+
|
51
|
+
should "allow all attributes when allowed option is not set" do
|
52
|
+
pipe = AttributeValidation.new
|
53
|
+
|
54
|
+
# Nothing should be raised now.
|
55
|
+
pipe.pipe({ :foo => "foo", :bar => "bar", :baz => "baz" })
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
context "with restricted attributes" do
|
61
|
+
setup do
|
62
|
+
@opts = {
|
63
|
+
:restricted => {
|
64
|
+
:bar => lambda { |value| ["qux", "bazqux"].include?(value) }
|
65
|
+
}
|
66
|
+
}
|
67
|
+
@pipe = AttributeValidation.new(@opts)
|
68
|
+
end
|
69
|
+
|
70
|
+
should "raise when lambda returns false" do
|
71
|
+
error = assert_raises(AttributeValidation::Failure) do
|
72
|
+
@pipe.pipe({ :bar => "foo"})
|
73
|
+
end
|
74
|
+
assert_equal "Invalid value for attribute bar.", error.message
|
75
|
+
|
76
|
+
# Nothing should be raised now.
|
77
|
+
@pipe.pipe({ :bar => "qux" })
|
78
|
+
@pipe.pipe({ :bar => "bazqux" })
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
should "return attributes hash when all is well" do
|
83
|
+
opts = {
|
84
|
+
:allowed => [:foo, :bar],
|
85
|
+
:required => [:foo],
|
86
|
+
:restricted => {
|
87
|
+
:bar => lambda { |value| ["bar", "foobar"].include?(value) }
|
88
|
+
}
|
89
|
+
}
|
90
|
+
pipe = AttributeValidation.new(opts)
|
91
|
+
attributes = { :foo => "bar", :bar => "foobar" }
|
92
|
+
assert_equal attributes, pipe.pipe(attributes)
|
93
|
+
end
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
@@ -0,0 +1,75 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
require 'json'
|
3
|
+
require 'virtus'
|
4
|
+
|
5
|
+
module Pyper::Pipes::Model
|
6
|
+
class VirtusDeserializerTest < Minitest::Should::TestCase
|
7
|
+
|
8
|
+
class TestVirtus
|
9
|
+
include ::Virtus.model
|
10
|
+
|
11
|
+
attribute :array, Array[String]
|
12
|
+
attribute :hash, Hash
|
13
|
+
attribute :int, Integer
|
14
|
+
attribute :float, Float
|
15
|
+
attribute :other, String
|
16
|
+
end
|
17
|
+
|
18
|
+
setup do
|
19
|
+
@pipe = VirtusDeserializer.new(TestVirtus.attribute_set)
|
20
|
+
end
|
21
|
+
|
22
|
+
should 'deserialize json arrays' do
|
23
|
+
value = [1,2,3]
|
24
|
+
item = { 'array' => JSON.generate(value) }
|
25
|
+
out = @pipe.pipe([item])
|
26
|
+
assert_equal 1, out.count
|
27
|
+
|
28
|
+
assert_equal value, out.first['array']
|
29
|
+
end
|
30
|
+
|
31
|
+
should 'deserialize json hashes' do
|
32
|
+
value = {'a' => 1}
|
33
|
+
item = { 'hash' => JSON.generate(value) }
|
34
|
+
out = @pipe.pipe([item])
|
35
|
+
assert_equal 1, out.count
|
36
|
+
assert_equal value, out.first['hash']
|
37
|
+
end
|
38
|
+
|
39
|
+
should 'deserialize ints' do
|
40
|
+
value = 1
|
41
|
+
item = { 'int' => value.to_s }
|
42
|
+
out = @pipe.pipe([item])
|
43
|
+
assert_equal 1, out.count
|
44
|
+
assert_equal value, out.first['int']
|
45
|
+
end
|
46
|
+
|
47
|
+
should 'deserialize floats' do
|
48
|
+
value = 1.5
|
49
|
+
item = { 'float' => value.to_s }
|
50
|
+
out = @pipe.pipe([item])
|
51
|
+
assert_equal 1, out.count
|
52
|
+
assert_equal value, out.first['float']
|
53
|
+
end
|
54
|
+
|
55
|
+
should 'not deserialize other fields' do
|
56
|
+
value = 'asdf'
|
57
|
+
item = { 'other' => value }
|
58
|
+
out = @pipe.pipe([item])
|
59
|
+
assert_equal 1, out.count
|
60
|
+
assert_equal value, out.first['other']
|
61
|
+
end
|
62
|
+
|
63
|
+
should 'not modify original values when deserializng' do
|
64
|
+
value = [1,2,3]
|
65
|
+
item = { 'array' => JSON.generate(value) }
|
66
|
+
out = @pipe.pipe([item])
|
67
|
+
assert_equal 1, out.count
|
68
|
+
assert_equal value, out.first['array']
|
69
|
+
|
70
|
+
# This throws an error if we have modified the original values
|
71
|
+
out = @pipe.pipe([item])
|
72
|
+
assert_equal value, out.first['array']
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes
|
4
|
+
class NoOpTest < Minitest::Should::TestCase
|
5
|
+
context 'NoOp pipe' do
|
6
|
+
should 'perform no operation' do
|
7
|
+
pipe_input = { :pipe_var => "this is a string" }
|
8
|
+
assert_equal pipe_input, NoOp.pipe(pipe_input)
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pyper::Pipes
|
4
|
+
class RemoveFieldsTest < Minitest::Should::TestCase
|
5
|
+
context 'the remove fields pipe' do
|
6
|
+
|
7
|
+
should "accept a symbol" do
|
8
|
+
pipe = RemoveFields.new(:a)
|
9
|
+
assert_equal({ :b => 2 }, pipe.pipe(:a => 1, :b => 2))
|
10
|
+
end
|
11
|
+
|
12
|
+
should "accept an array of symbol" do
|
13
|
+
pipe = RemoveFields.new([:a])
|
14
|
+
assert_equal({ :b => 2 }, pipe.pipe(:a => 1, :b => 2))
|
15
|
+
end
|
16
|
+
|
17
|
+
should 'remove fields provided an array of symbols' do
|
18
|
+
pipe = RemoveFields.new([:a])
|
19
|
+
assert_equal({ :b => 2 }, pipe.pipe(:a => 1, :b => 2))
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|