persistable 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore ADDED
@@ -0,0 +1,7 @@
1
+ *.gem
2
+ .bundle
3
+ Gemfile.lock
4
+ pkg/*
5
+ .rvmrc
6
+ .yardoc
7
+ doc
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source "http://rubygems.org"
2
+
3
+ # Specify your gem's dependencies in persistable.gemspec
4
+ gemspec
5
+ gem 'mogilefs-client', '2.2.0'
6
+ gem 'fog'
data/History.txt ADDED
@@ -0,0 +1,34 @@
1
+ == 0.5.9 2009-03-06
2
+
3
+ * 1 major enhancement:
4
+ * mogile-fs-adapter now opens and closes the connection for every action
5
+
6
+ == 0.5.7 2009-02-18
7
+
8
+ * 1 major enhancement:
9
+ * mogile-fs-adapter can now be given a timeout option
10
+
11
+ == 0.5.6 2009-01-29
12
+
13
+ * 1 major enhancement:
14
+ * mogile-fs-adapter now has the same handling for non-existant keys as the other adapters: returning nil
15
+
16
+ == 0.5.4 2009-01-29
17
+
18
+ * 1 minor enhancement:
19
+ * bumped version for great rebuild
20
+
21
+ == 0.5.3 2009-01-28
22
+
23
+ * 1 minor enhancement:
24
+ * Separated dependencies in dev and runtime dependencies
25
+
26
+ == 0.5.2 2009-01-28
27
+
28
+ * 1 major enhancement:
29
+ * Added missing gem dependencies
30
+
31
+ == 0.0.1 2009-01-06
32
+
33
+ * 1 major enhancement:
34
+ * Initial release
data/README.rdoc ADDED
@@ -0,0 +1,64 @@
1
+ = Persistable
2
+
3
+ == Description
4
+
5
+ Persistable is a library for persisting IO-Data into any storage you like. It provides adapters for in-memory storage, file storage, mogile-fs storage and a { fog gem }[http://fog.io] powered cloud storage but can be easily extended with your own adapters.
6
+
7
+ Persistable has been harvested from project pkw.de[http://pkw.de] of { Caroo GmbH }[http://caroo.com].
8
+
9
+ == Download and Installation
10
+
11
+ Install the gem with the following command...
12
+
13
+ $ gem install persistable --source http://github.com/pkwde/persistable
14
+
15
+ == Examples
16
+
17
+ class Image
18
+
19
+ attr_accessor :name, :persistence_adapter
20
+
21
+ def initialize(attributes = {})
22
+ @name = attributes[:name]
23
+ @persistence_data = attributes[:persistence_data]
24
+ end
25
+
26
+ def persistence_key
27
+ self.name
28
+ end
29
+
30
+ def persistence_data
31
+ @persistence_data
32
+ end
33
+
34
+ def persistence_data=(persistence_data)
35
+ @persistence_data = persistence_data
36
+ end
37
+
38
+ def save_image_data
39
+ persistence_adapter.write(self)
40
+ end
41
+
42
+ def load_image_data
43
+ persistence_adapter.load(self)
44
+ end
45
+
46
+ end
47
+
48
+
49
+ image = Image.new(:name => "foo", :persistence_data => File.open("/path/to/foo.jpg"))
50
+ image.persistence_adapter = Persistable::FSAdapter.new
51
+ image.save_image_data
52
+
53
+ new_but_same_image = Image.new(:name => "foo")
54
+ new_but_same_image.persistence_adapter = Persistable::FSAdapter.new
55
+ new_but_same_image.load_image_data
56
+
57
+ image.persistence_data == new_but_same_image.persistence_data
58
+
59
+
60
+ == License
61
+
62
+ Copyright Caroo GmbH 2009
63
+
64
+ You may use, copy and redistribute this library under the same terms as { Ruby itself }[http://www.ruby-lang.org/en/LICENSE.txt] or under the { MIT license }[http://mocha.rubyforge.org/files/MIT-LICENSE.html].
data/Rakefile ADDED
@@ -0,0 +1,11 @@
1
+ require 'bundler/gem_tasks'
2
+
3
+ require 'rake'
4
+ require 'rake/testtask'
5
+ desc "Run unit tests"
6
+ Rake::TestTask.new(:test) do |t|
7
+ t.libs << 'test'
8
+ t.test_files = FileList['test/*_test.rb']
9
+ t.verbose = true
10
+ t.warning = true
11
+ end
@@ -0,0 +1,13 @@
1
+ require "persistable/version"
2
+ require "persistable/xt/hash"
3
+
4
+ require "persistable/factory"
5
+
6
+ ##
7
+ # Persistable defines an abstract interface to save, retrieve and delete data from a storage.
8
+ # Currently memory, mogile_fs, file and cloud adapters are supported.
9
+ # The latter is powered by the {http://fog.io/storage/ fog gem}, so any fog storage provider can be used.
10
+ # Persistable has also a {Persistable::Factory factory class}, so you can use it to build your adapter using yml files.
11
+ module Persistable
12
+
13
+ end
@@ -0,0 +1,89 @@
1
+ require "fog"
2
+
3
+ module Persistable
4
+ ##
5
+ # CloudStorageAdapter powered by the fog gem
6
+ class CloudStorageAdapter
7
+
8
+ ##
9
+ # @!attribute [r] options
10
+ # @return [Hash] Options used during the object initialization
11
+ attr_reader :options
12
+
13
+ ##
14
+ # Creates a new `CloudStorageAdapter`
15
+ # @param options [Hash] `hash` with options for this adapter
16
+ # @option options [Symbol] :provider One of the providers given
17
+ # by {http://http://fog.io/storage/ fog gem}
18
+ # @option options [String] :directory The directory to save the files to,
19
+ # e.g. file system directory, amazon s3 bucket, ...
20
+ # @option options [Hash] :provider_options Provider options needed
21
+ # for {http://http://fog.io/storage/ fog gem} storage providers
22
+ def initialize(options = {})
23
+ @options = options
24
+ available_providers = Fog::Storage.providers
25
+ available_providers.include?(provider) or raise ArgumentError, "Unknown Fog::Storage provider. Should be on of \
26
+ #{available_providers.inspect}, given provider"
27
+ directory_name or raise ArgumentError, "Directory to save file should be given."
28
+ check_connection
29
+ end
30
+
31
+ ##
32
+ # Write the data given by `#persisence_data` method to the cloud
33
+ # @param persistable [#persistance_key, #persistance_data] Any object responding to the methods needed
34
+ # @return [Boolean] Returns the success status of this operation
35
+ def write(persistable)
36
+ if persistable.persistence_data
37
+ return directory.files.create(:key => persistable.persistence_key, :body => persistable.persistence_data)
38
+ end
39
+ return false
40
+ end
41
+
42
+ ##
43
+ # Reads the data on the cloud and write it on the `persistance_data` property of `persistable` object
44
+ # @param persistable (@see #write)
45
+ # @return (@see #write)
46
+ def read(persistable)
47
+ if file = directory.files.get(persistable.persistence_key)
48
+ persistable.persistence_data = StringIO.new(file.body)
49
+ return true
50
+ end
51
+ false
52
+ end
53
+
54
+ ##
55
+ # Deletes file named `persistable#persistance_key` from storage
56
+ # @param persistable (@see #write)
57
+ # @return (@see #write)
58
+ def delete(persistable)
59
+ if file = directory.files.head(persistable.persistence_key)
60
+ return file.destroy
61
+ end
62
+ false
63
+ end
64
+
65
+ private
66
+
67
+ def connection
68
+ @connection ||= Fog::Storage.new provider_options
69
+ end
70
+ alias check_connection connection
71
+
72
+ def directory
73
+ @directory ||= connection.directories.get(directory_name) || connection.directories.create(:key => directory_name)
74
+ end
75
+
76
+ def directory_name
77
+ @directory_name ||= options[:directory]
78
+ end
79
+
80
+ def provider
81
+ @provider ||= options[:provider].to_sym
82
+ end
83
+
84
+ def provider_options
85
+ options[:provider_options].merge({:provider => options[:provider]}).symbolize_keys
86
+ end
87
+
88
+ end
89
+ end
@@ -0,0 +1,52 @@
1
+ module Persistable
2
+ ##
3
+ # Factory class to help to define particular adapters.
4
+ # @deprecated This class has a strange API, so in the future a new API will be provided
5
+ class Factory
6
+
7
+ ##
8
+ # Builds a new adapter
9
+ # @param yml_file_path [String] the path to the config path in yml format.
10
+ # This file should include a `Hash` with a key `:adapter`, which is a `Hash` itself.
11
+ # The latter hash should contain a field named `type` specifying the adapter type.
12
+ # The adapter type is one of ['filesystem', 'mogilefs', 'memory', 'cloud']
13
+ # @param defaults [Hash={}] Hash with default values for given adapter. Those values will be reverse merged
14
+ # with values taken from yml file. The whole method is still useful just because of this param.
15
+ # Usually you will specify all values using `defaults` and leaving `yml_file_path` empty.
16
+ # @return [Adapter] Returns one of the adapter instances specified by the `type` option
17
+ def self.build(yml_file_path, defaults = {})
18
+ adapter_config = load_yml(yml_file_path, defaults)
19
+ raise ArgumentError.new("Invalid Parameter: There should be a Hash with :adapter key.") unless adapter_config[:adapter]
20
+ adapter_config = adapter_config[:adapter].symbolize_keys
21
+ raise ArgumentError.new("Invalid Parameter: There should be a Hash with :type key.") unless adapter_config[:type]
22
+
23
+ adapter = case adapter_config.delete(:type)
24
+ when 'filesystem'
25
+ require "persistable/fs_adapter"
26
+ Persistable::FSAdapter.new(adapter_config)
27
+ when 'mogilefs'
28
+ require "persistable/mogile_fs_adapter"
29
+ Persistable::MogileFSAdapter.new(adapter_config)
30
+ when 'memory'
31
+ require "persistable/memory_adapter"
32
+ Persistable::MemoryAdapter.new(adapter_config)
33
+ when 'cloud'
34
+ require "persistable/cloud_storage_adapter"
35
+ Persistable::CloudStorageAdapter.new(adapter_config)
36
+ end
37
+
38
+ return adapter
39
+ end
40
+
41
+ ##
42
+ # Loads the config from a yml file and returns the values as a `Hash`
43
+ # @param yml_file_path (@see #build)
44
+ # @param defaults (@see #build)
45
+ # @return [Hash] options needed to build an adapter
46
+ def self.load_yml(yml_file_path, defaults = {})
47
+ defaults.merge!(YAML.load_file(yml_file_path).symbolize_keys) if yml_file_path && File.exists?(yml_file_path)
48
+ return defaults
49
+ end
50
+
51
+ end
52
+ end
@@ -0,0 +1,29 @@
1
+ module Persistable
2
+ class FSAdapter
3
+
4
+ attr_reader :storage_location
5
+
6
+ def initialize(options = {})
7
+ @storage_location = options[:storage_location] || "/tmp"
8
+ end
9
+
10
+ def write(persistable)
11
+ File.open("#{storage_location}/#{persistable.persistence_key}", "w") do |file|
12
+ file.write persistable.persistence_data.read
13
+ end
14
+ end
15
+
16
+ def read(persistable)
17
+ if File.exists?(path = "#{storage_location}/#{persistable.persistence_key}")
18
+ persistable.persistence_data = File.open(path)
19
+ end
20
+ end
21
+
22
+ def delete(persistable)
23
+ if File.exists?(path = "#{storage_location}/#{persistable.persistence_key}")
24
+ File.delete("#{storage_location}/#{persistable.persistence_key}")
25
+ end
26
+ end
27
+
28
+ end
29
+ end
@@ -0,0 +1,23 @@
1
+ module Persistable
2
+ class MemoryAdapter
3
+
4
+ # Options are not used in this case, but we implement the constructor
5
+ # header in the same way the other adapters implement it.
6
+ def initialize(options = {})
7
+ @storage = {}
8
+ end
9
+
10
+ def write(persistable)
11
+ @storage[persistable.persistence_key] = persistable.persistence_data
12
+ end
13
+
14
+ def read(persistable)
15
+ persistable.persistence_data = @storage[persistable.persistence_key]
16
+ end
17
+
18
+ def delete(persistable)
19
+ @storage.delete(persistable.persistence_key)
20
+ end
21
+
22
+ end
23
+ end
@@ -0,0 +1,53 @@
1
+ require 'mogilefs'
2
+
3
+ module Persistable
4
+ class MogileFSAdapter
5
+
6
+ attr_reader :mogile_fs_class, :options
7
+
8
+
9
+ def initialize(options = {})
10
+ @options = options
11
+ @mogile_fs_class = options[:class]
12
+ end
13
+
14
+ def write(persistable)
15
+ hosts = options[:tracker].is_a?(String) ? [options[:tracker]] : options[:tracker]
16
+ connection = MogileFS::MogileFS.new(:domain => options[:domain], :hosts => hosts, :timeout => options[:timeout] ? options[:timeout] : 10)
17
+ status = connection.store_file(persistable.persistence_key, mogile_fs_class, persistable.persistence_data)
18
+ connection.backend.shutdown
19
+ status
20
+ end
21
+
22
+ def read(persistable)
23
+ hosts = options[:tracker].is_a?(String) ? [options[:tracker]] : options[:tracker]
24
+ connection = MogileFS::MogileFS.new(:domain => options[:domain], :hosts => hosts, :timeout => options[:timeout] ? options[:timeout] : 10)
25
+ begin
26
+ if data = connection.get_file_data(persistable.persistence_key)
27
+ persistable.persistence_data = StringIO.new(data)
28
+ else
29
+ persistable.persistence_data = nil
30
+ end
31
+ rescue MogileFS::Backend::UnknownKeyError, MogileFS::Backend::NoKeyError => e
32
+ persistable.persistence_data = nil
33
+ ensure
34
+ connection.backend.shutdown
35
+ end
36
+ end
37
+
38
+ def delete(persistable)
39
+ hosts = options[:tracker].is_a?(String) ? [options[:tracker]] : options[:tracker]
40
+ connection = MogileFS::MogileFS.new(:domain => options[:domain], :hosts => hosts, :timeout => options[:timeout] ? options[:timeout] : 10)
41
+ begin
42
+ status = connection.delete(persistable.persistence_key)
43
+ rescue MogileFS::Backend::UnknownKeyError => e
44
+ status = false
45
+ ensure
46
+ connection.backend.shutdown
47
+ end
48
+
49
+ status
50
+ end
51
+
52
+ end
53
+ end
@@ -0,0 +1,3 @@
1
+ module Persistable
2
+ VERSION = "0.7.0"
3
+ end
@@ -0,0 +1,11 @@
1
+ unless ::Hash.method_defined?(:symbolize_keys)
2
+ class ::Hash
3
+ def symbolize_keys
4
+ inject({}) { |hash, (key, value)| hash[key.to_s.to_sym] = value; hash }
5
+ end
6
+
7
+ def symbolize_keys!
8
+ replace symbolize_keys
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ $:.push File.expand_path("../lib", __FILE__)
3
+ require "persistable/version"
4
+
5
+ Gem::Specification.new do |s|
6
+ s.name = "persistable"
7
+ s.version = Persistable::VERSION
8
+ s.authors = ["pkw.de development team"]
9
+ s.email = ["dev@pkw.de"]
10
+ s.homepage = ""
11
+ s.summary = %q{Persistence gem for pkw.de images}
12
+ s.description = %q{Defines different ways to store images: file, memory, mogile_fs}
13
+
14
+ # s.add_dependency "mogilefs-client", "2.2.0"
15
+ s.add_development_dependency "rake"
16
+ s.add_development_dependency "test-unit"
17
+ s.add_development_dependency "mocha"
18
+ s.add_development_dependency "yard"
19
+
20
+ s.files = `git ls-files`.split("\n")
21
+ s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
22
+ s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
23
+ s.require_paths = ["lib"]
24
+ end
@@ -0,0 +1,91 @@
1
+ require "test_helper"
2
+
3
+ require 'test_helper'
4
+ require 'persistable/cloud_storage_adapter'
5
+ require 'fileutils'
6
+
7
+ class CloudStorageTest < Test::Unit::TestCase
8
+ def test_write_file
9
+ persistable = get_persistable
10
+ persistable.persistence_data = File.open(__FILE__)
11
+ assert adapter.write persistable
12
+ assert_true File.exist?(file_path)
13
+ end
14
+
15
+ def test_read_file
16
+ prepare_file
17
+ persistable = get_persistable
18
+ assert adapter.read persistable
19
+ assert persistable.persistence_data
20
+ assert_equal persistable.persistence_data.read, File.read(file_path)
21
+ end
22
+
23
+ def test_read_not_existent_path
24
+ assert_nothing_raised do
25
+ delete_file
26
+ persistable = get_persistable
27
+ assert_false adapter.read persistable
28
+ assert_nil persistable.persistence_data
29
+ end
30
+ end
31
+
32
+ def assert_delete
33
+ prepare_file
34
+ persistable = get_persistable
35
+ assert_true adapter.delete persistable
36
+ assert_false File.exist?(file_path)
37
+ end
38
+
39
+ def test_initializer_should_check_provider
40
+ assert_raise ArgumentError do
41
+ Persistable::CloudStorageAdapter.new(:provider => :now_known_provider)
42
+ end
43
+ end
44
+
45
+ def test_initializer_should_check_directory_name
46
+ assert_raise ArgumentError do
47
+ Persistable::CloudStorageAdapter.new(:provider => :aws)
48
+ end
49
+ end
50
+
51
+ def test_initializer_should_not_raise_errors_if_all_required_options_given
52
+ assert_nothing_raised do
53
+ Persistable::CloudStorageAdapter.new(valid_options)
54
+ end
55
+ end
56
+
57
+ private
58
+
59
+ def get_persistable
60
+ persistable = PersistableClass.new
61
+ persistable.persistence_key = "my_file_name"
62
+ persistable
63
+ end
64
+
65
+ def file_path
66
+ '/tmp/my_storage_dir/my_file_name'
67
+ end
68
+
69
+ def delete_file
70
+ FileUtils.rm_f file_path
71
+ end
72
+
73
+ def prepare_file
74
+ FileUtils.cp __FILE__, file_path
75
+ assert_true File.exist?(file_path)
76
+ end
77
+
78
+ def adapter
79
+ Persistable::CloudStorageAdapter.new valid_options
80
+ end
81
+
82
+ def valid_options
83
+ {
84
+ :provider => :local,
85
+ :directory => 'my_storage_dir',
86
+ :provider_options => {
87
+ :local_root => '/tmp'
88
+ }
89
+ }
90
+ end
91
+ end
@@ -0,0 +1,76 @@
1
+ require 'test_helper'
2
+ require 'persistable/factory'
3
+
4
+ class FactoryTest < Test::Unit::TestCase
5
+
6
+ def test_should_build_filesystem_adapter_from_yml
7
+ yml_file_name = "adapter.yml"
8
+ Persistable::Factory.expects(:load_yml).with(yml_file_name, {}).returns({:adapter => {:type => "filesystem"}})
9
+ persistable = Persistable::Factory.build(yml_file_name, {})
10
+ assert_kind_of Persistable::FSAdapter, persistable
11
+ end
12
+
13
+ def test_should_build_memory_adapter_from_yml
14
+ yml_file_name = "adapter.yml"
15
+ Persistable::Factory.expects(:load_yml).with(yml_file_name, {}).returns({:adapter => {:type => "memory"}})
16
+ persistable = Persistable::Factory.build(yml_file_name, {})
17
+ assert_kind_of Persistable::MemoryAdapter, persistable
18
+ end
19
+
20
+ def test_should_build_mogilefs_adapter_from_yml
21
+ yml_file_name = "adapter.yml"
22
+ Persistable::Factory.expects(:load_yml).with(yml_file_name, {}).returns({:adapter => {:type => "mogilefs", :tracker => "tracker1:6001", :class => "foo", :domain => "bar"}})
23
+ persistable_adapter = mock("persistable_adapter")
24
+ Persistable::MogileFSAdapter.expects(:new).with({:tracker => "tracker1:6001", :class => "foo", :domain => "bar"}).returns(persistable_adapter)
25
+ persistable = Persistable::Factory.build(yml_file_name, {})
26
+ assert_equal persistable_adapter, persistable
27
+ end
28
+
29
+ def test_should_load_yml_from_filename
30
+ File.expects(:exists?).returns(true)
31
+ mock_hash = mock("MockHash")
32
+ mock_hash.expects(:symbolize_keys).returns({})
33
+ YAML.expects(:load_file).with("adapter.yml").returns(mock_hash)
34
+ Persistable::Factory.load_yml("adapter.yml")
35
+ end
36
+
37
+ def test_should_just_return_defaults_in_load_yml_if_file_does_not_exist
38
+ file_mock = mock("File_mock")
39
+ File.expects(:exists?).returns(false)
40
+ defaults = mock("Defaults")
41
+ loaded_config = Persistable::Factory.load_yml("adapter.yml", defaults)
42
+ assert_equal defaults, loaded_config
43
+ end
44
+
45
+ def test_should_build_adapter_from_defaults
46
+ defaults = mock("defaults")
47
+ Persistable::Factory.expects(:load_yml).with(nil, defaults).returns({:adapter => {:type => "memory"}})
48
+ Persistable::Factory.build(nil, defaults)
49
+ end
50
+
51
+ def test_build_should_raise_exception_if_wrong_parameter
52
+ Persistable::Factory.expects(:load_yml).with("file_path", {}).returns(:wrong => :hash)
53
+ assert_raise(ArgumentError) { Persistable::Factory.build("file_path") }
54
+ Persistable::Factory.expects(:load_yml).with("file_path", {}).returns(:adapter => {:no_type => "but_adapter"})
55
+ assert_raise(ArgumentError) { Persistable::Factory.build("file_path") }
56
+ end
57
+
58
+ def test_should_build_cloud_storage_adapter_using_yml
59
+ yml_file_name = "adapter.yml"
60
+ Persistable::Factory.expects(:load_yml).with(yml_file_name, {}).returns(
61
+ {:adapter =>
62
+ {
63
+ :type => "cloud",
64
+ :directory => "store_directory",
65
+ :provider => "local",
66
+ :provider_options => {
67
+ :local_root => "/tmp"
68
+ }
69
+ }
70
+ }
71
+ )
72
+
73
+ persistable = Persistable::Factory.build(yml_file_name, {})
74
+ assert_kind_of Persistable::CloudStorageAdapter, persistable
75
+ end
76
+ end
@@ -0,0 +1,73 @@
1
+ require 'test_helper'
2
+ require 'persistable/fs_adapter'
3
+
4
+ class FSAdapterTest < Test::Unit::TestCase
5
+
6
+ def test_should_write_persistable_objects
7
+ adapter = Persistable::FSAdapter.new
8
+ adapter.expects(:storage_location).returns("/tmp")
9
+
10
+ persistable_object = mock("Persistable")
11
+ persistable_object.expects(:persistence_key).returns("42")
12
+ persistable_object.expects(:persistence_data).returns(StringIO.new("The answer to all questions."))
13
+
14
+ adapter.write(persistable_object)
15
+
16
+ assert File.exists?("/tmp/42")
17
+ assert_equal "The answer to all questions.", File.open("/tmp/42").read
18
+ end
19
+
20
+ def test_should_read_persistable_objects
21
+ adapter = Persistable::FSAdapter.new
22
+ adapter.expects(:storage_location).returns("/tmp")
23
+
24
+ File.open("/tmp/just_a_file", "wb") { |file| file.puts "test" }
25
+ just_a_file = File.open("/tmp/just_a_file")
26
+ File.expects(:open).with("/tmp/just_a_file").returns(just_a_file)
27
+
28
+ persistable_object = mock("Persistable")
29
+ persistable_object.expects(:persistence_key).returns("just_a_file")
30
+ persistable_object.expects(:persistence_data=).with(just_a_file)
31
+
32
+ adapter.read(persistable_object)
33
+ end
34
+
35
+ def test_should_not_read_not_existing_persistable_objects
36
+ adapter = Persistable::FSAdapter.new
37
+ adapter.expects(:storage_location).at_least_once.returns("/tmp")
38
+
39
+ persistable_object = mock("Persistable")
40
+ persistable_object.expects(:persistence_key).returns("just_a_not_existing_key")
41
+ persistable_object.expects(:persistence_data=).never
42
+
43
+ adapter.read(persistable_object)
44
+ end
45
+
46
+ def test_should_delete_persistable_objects
47
+ adapter = Persistable::FSAdapter.new
48
+ adapter.expects(:storage_location).times(3).returns("/tmp")
49
+
50
+ persistable_object = mock("Persistable")
51
+ persistable_object.expects(:persistence_key).times(3).returns("42")
52
+ persistable_object.expects(:persistence_data).returns(StringIO.new("The answer to all questions."))
53
+
54
+ adapter.write(persistable_object)
55
+
56
+ assert File.exists?("/tmp/42")
57
+ assert_equal "The answer to all questions.", File.open("/tmp/42").read
58
+
59
+ adapter.delete(persistable_object)
60
+ assert !File.exists?("/tmp/42")
61
+ end
62
+
63
+ def test_should_set_location_for_persisting_data
64
+ adapter = Persistable::FSAdapter.new(:storage_location => "/custom/location")
65
+ assert_equal "/custom/location", adapter.storage_location
66
+ end
67
+
68
+ def test_should_have_default_storage_location_set_to_global_tmp_dir
69
+ adapter = Persistable::FSAdapter.new
70
+ assert_equal "/tmp", adapter.storage_location
71
+ end
72
+
73
+ end
@@ -0,0 +1,46 @@
1
+ require 'test_helper'
2
+ require 'persistable/memory_adapter'
3
+
4
+ class MemoryAdapterTest < Test::Unit::TestCase
5
+
6
+ def test_should_write_persistable_objects
7
+ adapter = Persistable::MemoryAdapter.new
8
+
9
+ persistable_object = mock("Persistable")
10
+ persistable_object.expects(:persistence_key).returns("42")
11
+ persistable_object.expects(:persistence_data).returns(StringIO.new("The answer to all questions."))
12
+
13
+ adapter.write(persistable_object)
14
+
15
+ assert_equal "The answer to all questions.", adapter.instance_variable_get("@storage")["42"].read
16
+ end
17
+
18
+ def test_should_read_persistable_objects
19
+ adapter = Persistable::MemoryAdapter.new
20
+
21
+ test_io_object = StringIO.new("The answer to all questions.")
22
+ adapter.instance_variable_set("@storage", {"42" => test_io_object})
23
+
24
+ persistable_object = mock("Persistable")
25
+ persistable_object.expects(:persistence_key).returns("42")
26
+ persistable_object.expects(:persistence_data=).with(test_io_object)
27
+
28
+ adapter.read(persistable_object)
29
+ end
30
+
31
+ def test_should_delete_persistable_objects
32
+ adapter = Persistable::MemoryAdapter.new
33
+
34
+ persistable_object = mock("Persistable")
35
+ persistable_object.expects(:persistence_key).times(2).returns("42")
36
+ persistable_object.expects(:persistence_data).returns(StringIO.new("The answer to all questions."))
37
+
38
+ adapter.write(persistable_object)
39
+
40
+ assert_equal "The answer to all questions.", adapter.instance_variable_get("@storage")["42"].read
41
+
42
+ adapter.delete(persistable_object)
43
+ assert !adapter.instance_variable_get("@storage").has_key?("42")
44
+ end
45
+
46
+ end
@@ -0,0 +1,98 @@
1
+ require 'test_helper'
2
+ require 'persistable/mogile_fs_adapter'
3
+
4
+ class MogileFSAdapterTest < Test::Unit::TestCase
5
+
6
+ def test_should_write_and_read_and_delete_persistable_objects
7
+ adapter = Persistable::MogileFSAdapter.new(:domain => "mydomain", :tracker => "tracker.test.de:6001", :class => 'devel')
8
+
9
+ data_to_persist = StringIO.new("The answer to all questions.")
10
+ persistable_object_in = mock("PersistableIn")
11
+ persistable_object_in.expects(:persistence_key).returns("42")
12
+ persistable_object_in.expects(:persistence_data).returns(data_to_persist)
13
+
14
+ connection_in = mock("MogileFS-Connection")
15
+ connection_in.expects(:store_file).with("42", "devel", data_to_persist)
16
+ connection_in.expects(:backend).returns(mock("MockBackend", :shutdown => true))
17
+ MogileFS::MogileFS.expects(:new).at_least_once.with(:domain => "mydomain", :hosts => ["tracker.test.de:6001"], :timeout => 10).returns(connection_in)
18
+
19
+ adapter.write(persistable_object_in)
20
+
21
+ persistable_object_out = mock("PersistableOut")
22
+ persistable_object_out.expects(:persistence_key).returns("42")
23
+ persistable_object_out.expects(:persistence_data=).with() { |data| data.kind_of? StringIO }
24
+
25
+ connection_out = mock("MogileFS-Connection")
26
+ connection_out.expects(:get_file_data).with("42").returns(data_to_persist.read)
27
+ connection_out.expects(:backend).returns(mock("MockBackend", :shutdown => true))
28
+ MogileFS::MogileFS.expects(:new).at_least_once.with(:domain => "mydomain", :hosts => ["tracker.test.de:6001"], :timeout => 10).returns(connection_out)
29
+
30
+ adapter.read(persistable_object_out)
31
+
32
+ persistable_object_delete = mock("PersistableOut")
33
+ persistable_object_delete.expects(:persistence_key).returns("42")
34
+
35
+ connection_delete = mock("MogileFS-Connection")
36
+ connection_delete.expects(:delete).with("42")
37
+ connection_delete.expects(:backend).returns(mock("MockBackend", :shutdown => true))
38
+ MogileFS::MogileFS.expects(:new).at_least_once.with(:domain => "mydomain", :hosts => ["tracker.test.de:6001"], :timeout => 10).returns(connection_delete)
39
+
40
+ adapter.delete(persistable_object_delete)
41
+ end
42
+
43
+ def test_should_set_domain_tracker_and_class
44
+ adapter = Persistable::MogileFSAdapter.new(:domain => "mydomain", :tracker => "tracker.test.de:6001", :class => 'devel')
45
+ assert_equal "devel", adapter.mogile_fs_class
46
+ end
47
+
48
+ def test_should_set_domain_multiple_tracker_and_class
49
+ adapter = Persistable::MogileFSAdapter.new(:domain => "mydomain", :tracker => ["tracker1.test.de:6001", "tracker2.test.com:6001"], :class => 'devel')
50
+ assert_equal "devel", adapter.mogile_fs_class
51
+ end
52
+
53
+ def test_should_set_timeout
54
+ adapter = Persistable::MogileFSAdapter.new(:domain => "mydomain", :tracker => "tracker.test.de:6001", :class => 'devel', :timeout => 10)
55
+ assert_equal "devel", adapter.mogile_fs_class
56
+ end
57
+
58
+ def test_should_handle_unknown_key_on_delete_gracefully
59
+ adapter = Persistable::MogileFSAdapter.new(:domain => "mydomain", :tracker => "tracker.test.de:6001", :class => 'devel')
60
+ connection_delete = mock("MogileFS-Connection")
61
+ persistable_object_delete = mock("PersistableOut")
62
+ persistable_object_delete.expects(:persistence_key).returns("42")
63
+ connection_delete.expects(:delete).raises(MogileFS::Backend::UnknownKeyError)
64
+ connection_delete.expects(:backend).returns(mock("MockBackend", :shutdown => true))
65
+ MogileFS::MogileFS.expects(:new).at_least_once.with(:domain => "mydomain", :hosts => ["tracker.test.de:6001"], :timeout => 10).returns(connection_delete)
66
+
67
+ assert_equal(false, adapter.delete(persistable_object_delete))
68
+ end
69
+
70
+ def test_should_handle_unknown_key_on_read_gracefully
71
+ adapter = Persistable::MogileFSAdapter.new(:domain => "mydomain", :tracker => "tracker.test.de:6001", :class => 'devel')
72
+ connection_delete = mock("MogileFS-Connection")
73
+ persistable_object_read = mock("PersistableOut")
74
+ persistable_object_read.expects(:persistence_key).returns("42")
75
+ persistable_object_read.expects(:persistence_data=).with(nil)
76
+ connection_delete.expects(:get_file_data).raises(MogileFS::Backend::UnknownKeyError)
77
+ connection_delete.expects(:backend).returns(mock("MockBackend", :shutdown => true))
78
+ MogileFS::MogileFS.expects(:new).at_least_once.with(:domain => "mydomain", :hosts => ["tracker.test.de:6001"], :timeout => 10).returns(connection_delete)
79
+
80
+ assert_nothing_raised(MogileFS::Backend::UnknownKeyError) { adapter.read(persistable_object_read) }
81
+ end
82
+
83
+ def test_should_return_nil_if_file_was_not_found
84
+ adapter = Persistable::MogileFSAdapter.new(:domain => "mydomain", :tracker => "tracker.test.de:6001", :class => 'devel')
85
+
86
+
87
+ persistable_object_out = mock("PersistableOut")
88
+ persistable_object_out.expects(:persistence_key).returns("42")
89
+ persistable_object_out.expects(:persistence_data=).with(nil)
90
+
91
+ connection_out = mock("MogileFS-Connection")
92
+ connection_out.expects(:get_file_data).with("42").returns(nil)
93
+ connection_out.expects(:backend).returns(mock("MockBackend", :shutdown => true))
94
+ MogileFS::MogileFS.expects(:new).with(:domain => "mydomain", :hosts => ["tracker.test.de:6001"], :timeout => 10).returns(connection_out)
95
+ adapter.read(persistable_object_out)
96
+ end
97
+
98
+ end
@@ -0,0 +1,11 @@
1
+ require 'rubygems'
2
+ require 'test/unit'
3
+ require 'mocha/setup'
4
+
5
+ $:.unshift File.expand_path(File.join(File.dirname(__FILE__), "..", "lib"))
6
+
7
+ require 'persistable'
8
+
9
+ class PersistableClass
10
+ attr_accessor :persistence_data, :persistence_key
11
+ end
metadata ADDED
@@ -0,0 +1,146 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: persistable
3
+ version: !ruby/object:Gem::Version
4
+ hash: 3
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 7
9
+ - 0
10
+ version: 0.7.0
11
+ platform: ruby
12
+ authors:
13
+ - pkw.de development team
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-02-07 00:00:00 Z
19
+ dependencies:
20
+ - !ruby/object:Gem::Dependency
21
+ name: rake
22
+ version_requirements: &id001 !ruby/object:Gem::Requirement
23
+ none: false
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ hash: 3
28
+ segments:
29
+ - 0
30
+ version: "0"
31
+ type: :development
32
+ requirement: *id001
33
+ prerelease: false
34
+ - !ruby/object:Gem::Dependency
35
+ name: test-unit
36
+ version_requirements: &id002 !ruby/object:Gem::Requirement
37
+ none: false
38
+ requirements:
39
+ - - ">="
40
+ - !ruby/object:Gem::Version
41
+ hash: 3
42
+ segments:
43
+ - 0
44
+ version: "0"
45
+ type: :development
46
+ requirement: *id002
47
+ prerelease: false
48
+ - !ruby/object:Gem::Dependency
49
+ name: mocha
50
+ version_requirements: &id003 !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ hash: 3
56
+ segments:
57
+ - 0
58
+ version: "0"
59
+ type: :development
60
+ requirement: *id003
61
+ prerelease: false
62
+ - !ruby/object:Gem::Dependency
63
+ name: yard
64
+ version_requirements: &id004 !ruby/object:Gem::Requirement
65
+ none: false
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ hash: 3
70
+ segments:
71
+ - 0
72
+ version: "0"
73
+ type: :development
74
+ requirement: *id004
75
+ prerelease: false
76
+ description: "Defines different ways to store images: file, memory, mogile_fs"
77
+ email:
78
+ - dev@pkw.de
79
+ executables: []
80
+
81
+ extensions: []
82
+
83
+ extra_rdoc_files: []
84
+
85
+ files:
86
+ - .gitignore
87
+ - Gemfile
88
+ - History.txt
89
+ - README.rdoc
90
+ - Rakefile
91
+ - lib/persistable.rb
92
+ - lib/persistable/cloud_storage_adapter.rb
93
+ - lib/persistable/factory.rb
94
+ - lib/persistable/fs_adapter.rb
95
+ - lib/persistable/memory_adapter.rb
96
+ - lib/persistable/mogile_fs_adapter.rb
97
+ - lib/persistable/version.rb
98
+ - lib/persistable/xt/hash.rb
99
+ - persistable.gemspec
100
+ - test/cloud_storage_test.rb
101
+ - test/factory_test.rb
102
+ - test/fs_adapter_test.rb
103
+ - test/memory_adapter_test.rb
104
+ - test/mogile_fs_adapter_test.rb
105
+ - test/test_helper.rb
106
+ homepage: ""
107
+ licenses: []
108
+
109
+ post_install_message:
110
+ rdoc_options: []
111
+
112
+ require_paths:
113
+ - lib
114
+ required_ruby_version: !ruby/object:Gem::Requirement
115
+ none: false
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ hash: 3
120
+ segments:
121
+ - 0
122
+ version: "0"
123
+ required_rubygems_version: !ruby/object:Gem::Requirement
124
+ none: false
125
+ requirements:
126
+ - - ">="
127
+ - !ruby/object:Gem::Version
128
+ hash: 3
129
+ segments:
130
+ - 0
131
+ version: "0"
132
+ requirements: []
133
+
134
+ rubyforge_project:
135
+ rubygems_version: 1.8.24
136
+ signing_key:
137
+ specification_version: 3
138
+ summary: Persistence gem for pkw.de images
139
+ test_files:
140
+ - test/cloud_storage_test.rb
141
+ - test/factory_test.rb
142
+ - test/fs_adapter_test.rb
143
+ - test/memory_adapter_test.rb
144
+ - test/mogile_fs_adapter_test.rb
145
+ - test/test_helper.rb
146
+ has_rdoc: