storexplore 0.1.1 → 0.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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 7ffcb1b7ac49f590bdeafde98b7c6e3f6a4aecb8
4
- data.tar.gz: fbb03b9a51c7eab05ffea0d1498cf5b8f15413ec
3
+ metadata.gz: f9aad6223151eb82e5a00d692857bae568271a7f
4
+ data.tar.gz: 02565e1894429c9afbafe786817a7991c41248f4
5
5
  SHA512:
6
- metadata.gz: 94933a0836b830b49ac03fe4f604bf9f8be35cf6e1518a1ceb92b42ae03f76deb7d10e7e9a38cbff4753ea1a8eb3c4607d82445e28397ff3e45f1053bb2306ce
7
- data.tar.gz: 94c3a3291e638198fba5b19071449eeaa40cfbaac57db6cb28cb4f7294c515d4a895524448e618aad404dd412bff240eb386e99a329046dda79ba2a0e2e2766e
6
+ metadata.gz: 232031993870546c1bd5abcf442f5710eac133dd75bcd3342aacd41e7d87ec7c68bff2b7b8c911ecb8b3fadc20f3c6a1763b2474a2b9c065204ac756aacddbb1
7
+ data.tar.gz: 52d3a90be6cc7bc8c4805752c7fab05083efc6d8f9f0c5d3e255d19abaecd470538850edc8c2b234b6ae01d329e33eef37688eff384640474d16acca1dae9e28
Binary file
data.tar.gz.sig CHANGED
Binary file
@@ -20,6 +20,7 @@
20
20
  # MA 02110-1301 USA
21
21
 
22
22
  require 'storexplore'
23
+ require 'storexplore/testing/api_shared_context'
23
24
  require 'storexplore/testing/api_shared_examples'
24
25
  require 'storexplore/testing/configuration'
25
26
  require 'storexplore/testing/dummy_data'
@@ -0,0 +1,83 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # api_shared_context.rb
4
+ #
5
+ # Copyright (c) 2010-2014 by Philippe Bourgau. All rights reserved.
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation; either
10
+ # version 3.0 of the License, or (at your option) any later version.
11
+ #
12
+ # This library is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public
18
+ # License along with this library; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ # MA 02110-1301 USA
21
+
22
+ module Storexplore
23
+ module Testing
24
+
25
+ shared_context "a scrapped store" do
26
+
27
+ before :all do
28
+ @range = 0..1
29
+
30
+ expect(self).to(respond_to(:generate_store), "You should implement generate_store to include the scrapped store shared context")
31
+
32
+ self.store = generate_store
33
+ explore_store
34
+ end
35
+
36
+ def explore_store
37
+ @sample_categories = dig([store], :categories)
38
+ @all_sample_categories, @sample_items = dig_deep(@sample_categories)
39
+ @valid_sample_items = valid_items(@sample_items)
40
+ @sample_items_attributes = (valid_sample_items.map &:attributes).uniq
41
+ @parseable_categories_attributes = all_sample_categories.map do |category|
42
+ category.attributes rescue {}
43
+ end
44
+ end
45
+
46
+ attr_accessor :store, :sample_categories, :all_sample_categories, :sample_items, :valid_sample_items, :sample_items_attributes, :parseable_categories_attributes
47
+
48
+ def dig(categories, message)
49
+ categories.map { |cat| cat.send(message).to_a[@range] }.flatten
50
+ end
51
+
52
+ def dig_deep(categories)
53
+ all_categories = [categories]
54
+
55
+ while (items = dig(categories, :items)).empty?
56
+ categories = dig(categories, :categories)
57
+ all_categories << categories
58
+ end
59
+
60
+ [all_categories.flatten, items]
61
+ end
62
+
63
+ def valid_items(items)
64
+ result = []
65
+ sample_items.each do |item|
66
+ begin
67
+ item.attributes
68
+ result.push(item)
69
+ rescue BrowsingError => e
70
+ Testing.logger.debug e.message
71
+ end
72
+ end
73
+ result
74
+ end
75
+
76
+ def logger
77
+ Testing.config.logger
78
+ end
79
+
80
+ end
81
+
82
+ end
83
+ end
@@ -22,119 +22,54 @@
22
22
  module Storexplore
23
23
  module Testing
24
24
 
25
- module ApiSpecMacros
25
+ shared_examples "an API" do
26
26
 
27
- def self.included(base)
28
- base.send :extend, ClassMethods
27
+ it "should have many item categories" do
28
+ # TODO remove .first(3) once rspec handles lazy enums
29
+ expect(store.categories.first(3)).to have_at_least(3).items
29
30
  end
30
31
 
31
- module ClassMethods
32
-
33
- def it_should_behave_like_any_store_items_api
34
-
35
- before :all do
36
- @range = 0..1
37
-
38
- generate_store
39
- explore_store
40
- end
41
-
42
- it "should have many item categories" do
43
- # TODO remove .first(3) once rspec handles lazy enums
44
- expect(@store.categories.first(3)).to have_at_least(3).items
45
- end
46
-
47
- it "should have many items" do
48
- expect(sample_items).to have_at_least(3).items
49
- end
50
-
51
- it "should have item categories with different names" do
52
- categories_attributes = sample_categories.map { |cat| cat.attributes }
53
- expect(categories_attributes).to mostly have_unique(:name).in(categories_attributes)
54
- end
55
-
56
- it "should have items with different names" do
57
- expect(sample_items_attributes).to mostly have_unique(:name).in(sample_items_attributes)
58
- end
59
-
60
- it "should have parseable item category attributes" do
61
- expect(parseable_categories_attributes).to mostly have_key(:name)
62
- end
63
-
64
- it "should have some valid item attributes" do
65
- expect(sample_items_attributes).not_to be_empty
66
- end
67
-
68
- it "should have items with a price" do
69
- expect(sample_items_attributes).to all_ { have_key(:price) }
70
- end
71
-
72
- it "should mostly have items with an image" do
73
- expect(sample_items_attributes).to mostly have_key(:image)
74
- end
75
-
76
- it "should mostly have items with a brand" do
77
- expect(sample_items_attributes).to mostly have_key(:brand)
78
- end
79
-
80
- it "should have items with unique remote id" do
81
- expect(sample_items_attributes).to all_ { have_unique(:remote_id).in(sample_items_attributes) }
82
- end
83
-
84
- it "should have items with unique uris" do
85
- expect(valid_sample_items).to mostly have_unique(:uri).in(valid_sample_items)
86
- end
87
- end
32
+ it "should have many items" do
33
+ expect(sample_items).to have_at_least(3).items
88
34
  end
89
35
 
90
- def generate_store
91
- # by default, the store already exists
36
+ it "should have item categories with different names" do
37
+ categories_attributes = sample_categories.map { |cat| cat.attributes }
38
+ expect(categories_attributes).to mostly have_unique(:name).in(categories_attributes)
92
39
  end
93
40
 
94
- def explore_store
95
- @sample_categories = dig([@store], :categories)
96
- @all_sample_categories, @sample_items = dig_deep(@sample_categories)
97
- @valid_sample_items = valid_items(@sample_items)
98
- @sample_items_attributes = (valid_sample_items.map &:attributes).uniq
99
- @parseable_categories_attributes = all_sample_categories.map do |category|
100
- category.attributes rescue {}
101
- end
41
+ it "should have items with different names" do
42
+ expect(sample_items_attributes).to mostly have_unique(:name).in(sample_items_attributes)
102
43
  end
103
44
 
104
- attr_accessor :sample_categories, :all_sample_categories, :sample_items, :valid_sample_items, :sample_items_attributes, :parseable_categories_attributes
105
-
106
- def dig(categories, message)
107
- categories.map { |cat| cat.send(message).to_a[@range] }.flatten
45
+ it "should have parseable item category attributes" do
46
+ expect(parseable_categories_attributes).to mostly have_key(:name)
108
47
  end
109
48
 
110
- def dig_deep(categories)
111
- all_categories = [categories]
49
+ it "should have some valid item attributes" do
50
+ expect(sample_items_attributes).not_to be_empty
51
+ end
112
52
 
113
- while (items = dig(categories, :items)).empty?
114
- categories = dig(categories, :categories)
115
- all_categories << categories
116
- end
53
+ it "should have items with a price" do
54
+ expect(sample_items_attributes).to all_ { have_key(:price) }
55
+ end
117
56
 
118
- [all_categories.flatten, items]
57
+ it "should mostly have items with an image" do
58
+ expect(sample_items_attributes).to mostly have_key(:image)
119
59
  end
120
60
 
121
- def valid_items(items)
122
- result = []
123
- sample_items.each do |item|
124
- begin
125
- item.attributes
126
- result.push(item)
127
- rescue BrowsingError => e
128
- Testing.logger.debug e.message
129
- end
130
- end
131
- result
61
+ it "should mostly have items with a brand" do
62
+ expect(sample_items_attributes).to mostly have_key(:brand)
132
63
  end
133
64
 
134
- def logger
135
- Testing.config.logger
65
+ it "should have items with unique remote id" do
66
+ expect(sample_items_attributes).to all_ { have_unique(:remote_id).in(sample_items_attributes) }
136
67
  end
137
68
 
69
+ it "should have items with unique uris" do
70
+ expect(valid_sample_items).to mostly have_unique(:uri).in(valid_sample_items)
71
+ end
138
72
  end
73
+
139
74
  end
140
75
  end
@@ -20,5 +20,5 @@
20
20
  # MA 02110-1301 USA
21
21
 
22
22
  module Storexplore
23
- VERSION = "0.1.1"
23
+ VERSION = "0.2.0"
24
24
  end
@@ -0,0 +1,47 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # dummy_store_api_shared_context.rb
4
+ #
5
+ # Copyright (c) 2011-2014 by Philippe Bourgau. All rights reserved.
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation; either
10
+ # version 3.0 of the License, or (at your option) any later version.
11
+ #
12
+ # This library is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public
18
+ # License along with this library; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ # MA 02110-1301 USA
21
+
22
+ require 'spec_helper'
23
+
24
+ module Storexplore
25
+ module Testing
26
+
27
+ shared_context "a generated dummy store" do
28
+ def default_store_name
29
+ "www.spec-store.com"
30
+ end
31
+
32
+ def generate_store(store_name = default_store_name, item_count = 3)
33
+ DummyStore.wipe_out_store(store_name)
34
+ @store_generator = DummyStore.open(store_name)
35
+ @store_generator.generate(3).categories.and(3).categories.and(item_count).items
36
+
37
+ new_store(store_name)
38
+ end
39
+
40
+ def new_store(store_name = default_store_name)
41
+ Api.browse(DummyStore.uri(store_name))
42
+ end
43
+
44
+ end
45
+
46
+ end
47
+ end
@@ -20,27 +20,15 @@
20
20
  # MA 02110-1301 USA
21
21
 
22
22
  require 'spec_helper'
23
+ require_relative 'dummy_store_api_shared_context'
23
24
 
24
25
  module Storexplore
25
26
  module Testing
26
27
 
27
28
  describe "DummyStoreApi", slow: true do
28
- include ApiSpecMacros
29
-
30
- it_should_behave_like_any_store_items_api
31
-
32
- DEFAULT_STORE_NAME = "www.spec-store.com"
33
-
34
- def generate_store(store_name = DEFAULT_STORE_NAME, item_count = 3)
35
- DummyStore.wipe_out_store(store_name)
36
- @store_generator = DummyStore.open(store_name)
37
- @store_generator.generate(3).categories.and(3).categories.and(item_count).items
38
- @store = new_store(store_name)
39
- end
40
-
41
- def new_store(store_name = DEFAULT_STORE_NAME)
42
- Api.browse(DummyStore.uri(store_name))
43
- end
29
+ include_context "a generated dummy store"
30
+ include_context "a scrapped store"
31
+ it_should_behave_like "an API"
44
32
 
45
33
  it "should not truncate long item names" do
46
34
  @store_generator.
@@ -58,84 +46,6 @@ module Storexplore
58
46
  expect(item.attributes[:name]).to eq item_name
59
47
  end
60
48
 
61
- it "should use constant memory" do
62
- FEW = 10
63
- MANY = 100
64
- RUNS = 2
65
-
66
- many_inputs_memory = memory_usage_for_items(MANY, RUNS)
67
- few_inputs_memory = memory_usage_for_items(FEW, RUNS)
68
-
69
- slope = (many_inputs_memory - few_inputs_memory) / (MANY - FEW)
70
-
71
- zero_inputs_memory = few_inputs_memory - FEW * slope
72
-
73
- expect(slope).to be_within(zero_inputs_memory * 0.05).of(0.0)
74
- end
75
-
76
- def memory_usage_for_items(item_count, runs)
77
- generate_store(store_name = "www.spec-perf-store.com", item_count)
78
- data = runs.times.map do
79
- memory_peak_of do
80
- walk_store(store_name)
81
- end
82
- end
83
- mean(data)
84
- end
85
-
86
- def memory_peak_of
87
- peak_usage = 0
88
- finished = false
89
-
90
- initial_usage = current_living_objects
91
- profiler = Thread.new do
92
- while not finished
93
- peak_usage = [peak_usage, current_living_objects].max
94
- sleep(0.01)
95
- end
96
- end
97
-
98
- yield
99
-
100
- finished = true
101
- profiler.join
102
-
103
- peak_usage - initial_usage
104
- end
105
-
106
- def current_living_objects
107
- object_counts = ObjectSpace.count_objects
108
- object_counts[:TOTAL] - object_counts[:FREE]
109
- end
110
-
111
- def walk_store(store_name)
112
- new_store(store_name).categories.each do |category|
113
- register(category)
114
-
115
- category.categories.each do |sub_category|
116
- register(sub_category)
117
-
118
- sub_category.items.each do |item|
119
- register(item)
120
- end
121
- end
122
- end
123
- end
124
-
125
- def register(store_node)
126
- @title = store_node.title
127
- @attributes = store_node.attributes
128
-
129
- # No GC is explicitly done, because:
130
- # - large inputs forces it anyway
131
- # - it greatly slows tests
132
- # - GCing should not change the complexity of the system
133
- # GC.start
134
- end
135
-
136
- def mean(data)
137
- data.reduce(:+)/data.size
138
- end
139
49
  end
140
50
 
141
51
  end
@@ -0,0 +1,127 @@
1
+ # -*- encoding: utf-8 -*-
2
+ #
3
+ # memory_usage_spec.rb
4
+ #
5
+ # Copyright (c) 2011-2014 by Philippe Bourgau. All rights reserved.
6
+ #
7
+ # This library is free software; you can redistribute it and/or
8
+ # modify it under the terms of the GNU Lesser General Public
9
+ # License as published by the Free Software Foundation; either
10
+ # version 3.0 of the License, or (at your option) any later version.
11
+ #
12
+ # This library is distributed in the hope that it will be useful,
13
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
14
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15
+ # Lesser General Public License for more details.
16
+ #
17
+ # You should have received a copy of the GNU Lesser General Public
18
+ # License along with this library; if not, write to the Free Software
19
+ # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
20
+ # MA 02110-1301 USA
21
+
22
+ require 'spec_helper'
23
+ require_relative 'dummy_store_api_shared_context'
24
+
25
+ module Storexplore
26
+ module Testing
27
+
28
+ describe "DummyStoreApi", slow: true do
29
+ include_context "a generated dummy store"
30
+ include_context "a scrapped store"
31
+
32
+ DEFAULT_STORE_NAME = "www.spec-store.com"
33
+
34
+ def generate_store(store_name = DEFAULT_STORE_NAME, item_count = 3)
35
+ DummyStore.wipe_out_store(store_name)
36
+ @store_generator = DummyStore.open(store_name)
37
+ @store_generator.generate(3).categories.and(3).categories.and(item_count).items
38
+
39
+ new_store(store_name)
40
+ end
41
+
42
+ def new_store(store_name = DEFAULT_STORE_NAME)
43
+ Api.browse(DummyStore.uri(store_name))
44
+ end
45
+
46
+ it "should use constant memory" do
47
+ FEW = 10
48
+ MANY = 100
49
+ RUNS = 2
50
+
51
+ many_inputs_memory = memory_usage_for_items(MANY, RUNS)
52
+ few_inputs_memory = memory_usage_for_items(FEW, RUNS)
53
+
54
+ slope = (many_inputs_memory - few_inputs_memory) / (MANY - FEW)
55
+
56
+ zero_inputs_memory = few_inputs_memory - FEW * slope
57
+
58
+ expect(slope).to be_within(zero_inputs_memory * 0.05).of(0.0)
59
+ end
60
+
61
+ def memory_usage_for_items(item_count, runs)
62
+ generate_store(store_name = "www.spec-perf-store.com", item_count)
63
+ data = runs.times.map do
64
+ memory_peak_of do
65
+ walk_store(store_name)
66
+ end
67
+ end
68
+ mean(data)
69
+ end
70
+
71
+ def memory_peak_of
72
+ peak_usage = 0
73
+ finished = false
74
+
75
+ initial_usage = current_living_objects
76
+ profiler = Thread.new do
77
+ while not finished
78
+ peak_usage = [peak_usage, current_living_objects].max
79
+ sleep(0.01)
80
+ end
81
+ end
82
+
83
+ yield
84
+
85
+ finished = true
86
+ profiler.join
87
+
88
+ peak_usage - initial_usage
89
+ end
90
+
91
+ def current_living_objects
92
+ object_counts = ObjectSpace.count_objects
93
+ object_counts[:TOTAL] - object_counts[:FREE]
94
+ end
95
+
96
+ def walk_store(store_name)
97
+ new_store(store_name).categories.each do |category|
98
+ register(category)
99
+
100
+ category.categories.each do |sub_category|
101
+ register(sub_category)
102
+
103
+ sub_category.items.each do |item|
104
+ register(item)
105
+ end
106
+ end
107
+ end
108
+ end
109
+
110
+ def register(store_node)
111
+ @title = store_node.title
112
+ @attributes = store_node.attributes
113
+
114
+ # No GC is not explicitly done, because:
115
+ # - large inputs forces it anyway
116
+ # - it greatly slows tests
117
+ # - GCing should not change the complexity of the system
118
+ # GC.start
119
+ end
120
+
121
+ def mean(data)
122
+ data.reduce(:+)/data.size
123
+ end
124
+ end
125
+
126
+ end
127
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: storexplore
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Philou
@@ -31,7 +31,7 @@ cert_chain:
31
31
  yLcl1cmm5ALtJ/+Bkkmp0i4amXeTDMvq9r8PBsVsQwxYOYJBP+Umxz3PX6HjFHrQ
32
32
  XdkXx3oZ
33
33
  -----END CERTIFICATE-----
34
- date: 2014-01-16 00:00:00.000000000 Z
34
+ date: 2014-01-21 00:00:00.000000000 Z
35
35
  dependencies:
36
36
  - !ruby/object:Gem::Dependency
37
37
  name: mechanize
@@ -142,6 +142,7 @@ files:
142
142
  - lib/storexplore/hash_utils.rb
143
143
  - lib/storexplore/null_digger.rb
144
144
  - lib/storexplore/testing.rb
145
+ - lib/storexplore/testing/api_shared_context.rb
145
146
  - lib/storexplore/testing/api_shared_examples.rb
146
147
  - lib/storexplore/testing/configuration.rb
147
148
  - lib/storexplore/testing/dummy_data.rb
@@ -159,7 +160,9 @@ files:
159
160
  - spec/lib/storexplore/api_spec.rb
160
161
  - spec/lib/storexplore/dsl_spec.rb
161
162
  - spec/lib/storexplore/store_walker_page_spec_fixture.html
163
+ - spec/lib/storexplore/testing/dummy_store_api_shared_context.rb
162
164
  - spec/lib/storexplore/testing/dummy_store_api_spec.rb
165
+ - spec/lib/storexplore/testing/memory_usage_spec.rb
163
166
  - spec/lib/storexplore/uri_utils_spec.rb
164
167
  - spec/lib/storexplore/walker_page_spec.rb
165
168
  - spec/spec_helper.rb
@@ -192,7 +195,9 @@ test_files:
192
195
  - spec/lib/storexplore/api_spec.rb
193
196
  - spec/lib/storexplore/dsl_spec.rb
194
197
  - spec/lib/storexplore/store_walker_page_spec_fixture.html
198
+ - spec/lib/storexplore/testing/dummy_store_api_shared_context.rb
195
199
  - spec/lib/storexplore/testing/dummy_store_api_spec.rb
200
+ - spec/lib/storexplore/testing/memory_usage_spec.rb
196
201
  - spec/lib/storexplore/uri_utils_spec.rb
197
202
  - spec/lib/storexplore/walker_page_spec.rb
198
203
  - spec/spec_helper.rb
metadata.gz.sig CHANGED
Binary file