persistable 0.7.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.
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: