appengine-apis 0.0.1

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.
@@ -0,0 +1,123 @@
1
+ #!/usr/bin/ruby1.8 -w
2
+ #
3
+ # Copyright:: Copyright 2007 Google Inc.
4
+ # Original Author:: Ryan Brown (mailto:ribrdb@google.com)
5
+ #
6
+ # Licensed under the Apache License, Version 2.0 (the "License");
7
+ # you may not use this file except in compliance with the License.
8
+ # You may obtain a copy of the License at
9
+ #
10
+ # http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
+ # Unless required by applicable law or agreed to in writing, software
13
+ # distributed under the License is distributed on an "AS IS" BASIS,
14
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ # See the License for the specific language governing permissions and
16
+ # limitations under the License.
17
+ #
18
+ #
19
+ # Helpers for installing stub apis in unit tests.
20
+
21
+ require 'appengine-apis/apiproxy'
22
+
23
+ module AppEngine
24
+ module Testing
25
+ import com.google.appengine.tools.development.ApiProxyLocalFactory
26
+ import com.google.appengine.api.datastore.dev.LocalDatastoreService
27
+
28
+ class TestEnv # :nodoc:
29
+ include AppEngine::ApiProxy::Environment
30
+
31
+ attr_writer :appid, :version, :email, :admin, :logged_in
32
+ attr_writer :auth_domain, :request_namespace, :default_namespace
33
+
34
+ def initialize
35
+ @appid = "test"
36
+ @version = "1.0"
37
+ @auth_domain = "gmail.com"
38
+ end
39
+
40
+ def getAppId
41
+ @appid
42
+ end
43
+
44
+ def getVersionId
45
+ @version
46
+ end
47
+
48
+ def getEmail
49
+ @email
50
+ end
51
+
52
+ def isLoggedIn
53
+ @logged_in
54
+ end
55
+
56
+ def isAdmin
57
+ @admin
58
+ end
59
+
60
+ def getAuthDomain
61
+ @auth_domain
62
+ end
63
+
64
+ def getRequestNamespace
65
+ @request_namespace
66
+ end
67
+
68
+ def getDefaultNamespace
69
+ @default_namespace
70
+ end
71
+
72
+ def setDefaultNamespace(s)
73
+ @default_namespace = s
74
+ end
75
+ end
76
+
77
+ class << self
78
+ def install_test_env
79
+ env = TestEnv.new
80
+ ApiProxy::setEnvironmentForCurrentThread(env)
81
+ env
82
+ end
83
+
84
+ def factory
85
+ @factory ||= ApiProxyLocalFactory.new
86
+ end
87
+
88
+ def app_dir
89
+ file = factory.getApplicationDirectory
90
+ file && file.path
91
+ end
92
+
93
+ def app_dir=(dir)
94
+ factory.setApplicationDirectory(java.io.File.new(dir))
95
+ end
96
+
97
+ # Force all datastore operations to use an in-memory datastore.
98
+ def install_test_datastore
99
+ self.app_dir = '.' if app_dir.nil?
100
+ delegate = factory.create
101
+ delegate.set_property(
102
+ LocalDatastoreService::NO_STORAGE_PROPERTY, "true")
103
+ delegate.set_property(
104
+ LocalDatastoreService::MAX_QUERY_LIFETIME_PROPERTY,
105
+ java.lang.Integer::MAX_VALUE.to_s)
106
+ delegate.set_property(
107
+ LocalDatastoreService::MAX_TRANSACTION_LIFETIME_PROPERTY,
108
+ java.lang.Integer::MAX_VALUE.to_s)
109
+ ApiProxy::setDelegate(delegate)
110
+ delegate
111
+ end
112
+
113
+ def install_api_stubs
114
+ self.app_dir = '.' if app_dir.nil?
115
+ delegate = factory.create
116
+ ApiProxy::setDelegate(delegate)
117
+ delegate
118
+ end
119
+
120
+ end
121
+
122
+ end
123
+ end
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ # File: script/console
3
+ irb = RUBY_PLATFORM =~ /(:?mswin|mingw)/ ? 'irb.bat' : 'irb'
4
+
5
+ libs = " -r irb/completion"
6
+ # Perhaps use a console_lib to store any extra methods I may want available in the cosole
7
+ # libs << " -r #{File.dirname(__FILE__) + '/../lib/console_lib/console_logger.rb'}"
8
+ libs << " -r #{File.dirname(__FILE__) + '/../lib/appengine-apis.rb'}"
9
+ puts "Loading appengine-apis gem"
10
+ exec "#{irb} #{libs} --simple-prompt"
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/destroy'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Destroy.new.run(ARGV)
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+ APP_ROOT = File.expand_path(File.join(File.dirname(__FILE__), '..'))
3
+
4
+ begin
5
+ require 'rubigen'
6
+ rescue LoadError
7
+ require 'rubygems'
8
+ require 'rubigen'
9
+ end
10
+ require 'rubigen/scripts/generate'
11
+
12
+ ARGV.shift if ['--help', '-h'].include?(ARGV[0])
13
+ RubiGen::Base.use_component_sources! [:rubygems, :newgem, :newgem_theme, :test_unit]
14
+ RubiGen::Scripts::Generate.new.run(ARGV)
@@ -0,0 +1,150 @@
1
+ # Copyright:: Copyright 2009 Google Inc.
2
+ # Original Author:: Ryan Brown (mailto:ribrdb@google.com)
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require File.dirname(__FILE__) + '/spec_helper.rb'
17
+ require 'appengine-apis/datastore'
18
+
19
+ describe AppEngine::Datastore do
20
+ Datastore = AppEngine::Datastore
21
+
22
+ before :each do
23
+ AppEngine::Testing.install_test_datastore
24
+ end
25
+
26
+ it "should support get/put" do
27
+ entity = Datastore::Entity.new("Test")
28
+ entity[:a] = "a"
29
+ entity[:b] = "b"
30
+ key = Datastore.put(entity)
31
+ entity.key.should == key
32
+ stored = Datastore.get(key)
33
+ stored.should == entity
34
+ stored[:a].should == "a"
35
+ stored[:b].should == "b"
36
+ end
37
+
38
+ it "should put many" do
39
+ a = Datastore::Entity.new("A")
40
+ b = Datastore::Entity.new("B")
41
+ keys = Datastore.put(a, b)
42
+ keys.size.should == 2
43
+ keys[0].kind.should == "A"
44
+ keys[1].kind.should == "B"
45
+ got = Datastore.get(keys)
46
+ got.size.should == 2
47
+ got[0].should == a
48
+ got[1].should == b
49
+ end
50
+
51
+ it "should support failed transactions" do
52
+ pending("Real local transactions") do
53
+ a = Datastore::Entity.new("A")
54
+ a[:a] = 0
55
+ Datastore.put(a)
56
+ p = lambda do
57
+ Datastore.transaction do
58
+ a2 = Datastore.get(a.key)
59
+ a[:a] += 1
60
+ Datastore.put(nil, a)
61
+ Datastore.put(a2)
62
+ end
63
+ end
64
+ p.should raise_error Datastore::TransactionFailed
65
+ end
66
+ end
67
+
68
+ it "should retry transactions" do
69
+ pending("Real local transactions") do
70
+ a = Datastore::Entity.new("A")
71
+ a[:a] = 0
72
+ Datastore.put(a)
73
+ Datastore.transaction(3) do
74
+ a2 = Datastore.get(a.key)
75
+ a[:a] += 1
76
+ Datastore.put(nil, a) if a[:a] < 3
77
+ a2[:a] = "2: #{a2[:a]}"
78
+ Datastore.put(a2)
79
+ end
80
+
81
+ Datastore.get(a.key)[:a].should == '2: 2'
82
+ end
83
+ end
84
+
85
+ it "should close transactions" do
86
+ lambda {Datastore.transaction{ raise "Foo"}}.should raise_error "Foo"
87
+ Datastore.active_transactions.to_a.should == []
88
+ end
89
+ end
90
+
91
+ describe AppEngine::Datastore::Query do
92
+ Datastore = AppEngine::Datastore
93
+ Query = AppEngine::Datastore::Query
94
+
95
+ before :all do
96
+ AppEngine::Testing.install_test_datastore
97
+ @a = Datastore::Entity.new("A")
98
+ @a['name'] = 'a'
99
+ Datastore.put(@a)
100
+
101
+ @aa = Datastore::Entity.new("A", @a.key)
102
+ @aa['name'] = 'aa'
103
+
104
+ @b = Datastore::Entity.new("B")
105
+ @b['name'] = 'b'
106
+
107
+ @ab = Datastore::Entity.new("B", @a.key)
108
+ @ab['name'] = 'ab'
109
+ Datastore.put(@aa, @ab, @b)
110
+ end
111
+
112
+ it "should support chaining" do
113
+ q = Query.new("Foo")
114
+ q.set_ancestor(@a.key).sort('name').filter(
115
+ 'name', Query::EQUAL, 'Bob').should == q
116
+ end
117
+
118
+ it "should support ancestor" do
119
+ a = @a.key
120
+ q = Query.new("A", a)
121
+ q.java_query.ancestor.should == a
122
+ q.fetch.to_a.should == [@a, @aa]
123
+
124
+ q = Query.new("A")
125
+ q.set_ancestor(a)
126
+ q.java_query.ancestor.should == a
127
+ q.fetch.to_a.should == [@a, @aa]
128
+
129
+ q = Query.new("A")
130
+ q.ancestor = a
131
+ q.java_query.ancestor.should == a
132
+ q.fetch.to_a.should == [@a, @aa]
133
+ end
134
+
135
+ it "should support ancestor only" do
136
+ a = @a.key
137
+ q = Query.new(a)
138
+ q.java_query.ancestor.should == a
139
+ pending("Local ancestory only queries") do
140
+ q.fetch.to_a.should == [@a, @aa, @ab]
141
+ end
142
+ end
143
+
144
+ it "should support sort" do
145
+ q = Query.new("A")
146
+ q.sort('name', Query::DESCENDING)
147
+ q.fetch.to_a.should == [@aa, @a]
148
+ end
149
+
150
+ end
@@ -0,0 +1,198 @@
1
+ # Copyright:: Copyright 2009 Google Inc.
2
+ # Original Author:: Ryan Brown (mailto:ribrdb@google.com)
3
+ #
4
+ # Licensed under the Apache License, Version 2.0 (the "License");
5
+ # you may not use this file except in compliance with the License.
6
+ # You may obtain a copy of the License at
7
+ #
8
+ # http://www.apache.org/licenses/LICENSE-2.0
9
+ #
10
+ # Unless required by applicable law or agreed to in writing, software
11
+ # distributed under the License is distributed on an "AS IS" BASIS,
12
+ # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
+ # See the License for the specific language governing permissions and
14
+ # limitations under the License.
15
+
16
+ require File.dirname(__FILE__) + '/spec_helper.rb'
17
+ require 'appengine-apis/datastore_types'
18
+
19
+ describe AppEngine::Datastore::Key do
20
+ Key = AppEngine::Datastore::Key
21
+
22
+ it "should support ==" do
23
+ a1 = Key.from_path("A", 1)
24
+ a2 = Key.from_path("A", 1)
25
+ a1.should == a2
26
+ a2.should.eql? a1
27
+ a1.hash.should == a2.hash
28
+ pending("Key.compareTo") do
29
+ (a1 <=> a2).should == 0
30
+ end
31
+ end
32
+
33
+ it "should support <=>" do
34
+ pending("Key.compareTo") do
35
+ a1 = Key.from_path("A", 1)
36
+ a2 = Key.from_path("A", 2)
37
+ a1.should < a2
38
+ a2.should > a1
39
+ (a1 <=> a2).should == -1
40
+ (a2 <=> a1).should == 1
41
+ end
42
+ end
43
+
44
+ it "should create from id" do
45
+ key = Key.from_path("Foo", 27)
46
+ key.kind.should == 'Foo'
47
+ key.id.should == 27
48
+ key.id_or_name.should == 27
49
+ end
50
+
51
+ it "should create from name" do
52
+ key = Key.from_path("Bar", 'baz')
53
+ key.kind.should == 'Bar'
54
+ key.name.should == 'baz'
55
+ key.id_or_name.should == 'baz'
56
+ end
57
+
58
+ it "should create with parent" do
59
+ parent = Key.from_path("Foo", 1)
60
+ key = Key.from_path(parent, "Bar", 2)
61
+ key.kind.should == 'Bar'
62
+ key.id.should == 2
63
+ key.parent.should == parent
64
+ end
65
+
66
+ it "should support long paths" do
67
+ key = Key.from_path('A', 1, 'B', 2, 'C', 3)
68
+ key.kind.should == 'C'
69
+ key.id.should == 3
70
+ key.parent.kind.should == 'B'
71
+ key.parent.id.should == 2
72
+ key.parent.parent.kind.should == 'A'
73
+ key.parent.parent.id.should == 1
74
+ end
75
+
76
+ it "should encode" do
77
+ key = Key.from_path('Foo', 'bar')
78
+ key.to_s.should == 'agR0ZXN0cgwLEgNGb28iA2Jhcgw'
79
+ end
80
+
81
+ it "should create from encoded" do
82
+ decoded = Key.new('agR0ZXN0cgwLEgNGb28iA2Jhcgw')
83
+ key = Key.from_path('Foo', 'bar')
84
+ decoded.should == key
85
+ end
86
+
87
+ end
88
+
89
+ describe AppEngine::Datastore::Entity do
90
+
91
+ before :each do
92
+ @entity = AppEngine::Datastore::Entity.new('Test')
93
+ end
94
+
95
+ it "should support nil" do
96
+ @entity['nil'] = nil
97
+ @entity.has_property?('nil').should == true
98
+ @entity['nil'].should == nil
99
+ end
100
+
101
+ it "should support true" do
102
+ @entity['true'] = true
103
+ @entity['true'].should == true
104
+ end
105
+
106
+ it "should support false" do
107
+ @entity['false'] = false
108
+ @entity['false'].should == false
109
+ end
110
+
111
+ it "should support Strings" do
112
+ @entity['string'] = 'a string'
113
+ @entity['string'].should == 'a string'
114
+ end
115
+
116
+ it "should support Integers" do
117
+ @entity['int'] = 42
118
+ @entity['int'].should == 42
119
+ end
120
+
121
+ it "should support Floats" do
122
+ @entity['float'] = 3.1415
123
+ @entity['float'].should == 3.1415
124
+ end
125
+
126
+ it "should support Symbol for name" do
127
+ @entity[:foo] = 'bar'
128
+ @entity[:foo].should == 'bar'
129
+ @entity['foo'].should == 'bar'
130
+ end
131
+
132
+ it "should support Text" do
133
+ text = 'Some text. ' * 1000
134
+ @entity['text'] = AppEngine::Datastore::Text.new(text)
135
+ @entity['text'].should == text
136
+ @entity['text'].class.should == AppEngine::Datastore::Text
137
+ end
138
+
139
+ it "should support Blob" do
140
+ blob = "\0\1\2" * 1000
141
+ @entity['blob'] = AppEngine::Datastore::Blob.new(blob)
142
+ @entity['blob'].should == blob
143
+ @entity['blob'].class.should == AppEngine::Datastore::Blob
144
+ end
145
+
146
+ it "should support ByteString" do
147
+ blob = "\0\1\2"
148
+ @entity['blob'] = AppEngine::Datastore::ByteString.new(blob)
149
+ @entity['blob'].should == blob
150
+ @entity['blob'].class.should == AppEngine::Datastore::ByteString
151
+ end
152
+
153
+ it "should support Link" do
154
+ link = "http://example.com/" + "0" * 1000
155
+ @entity['link'] = AppEngine::Datastore::Link.new(link)
156
+ @entity['link'].should == link
157
+ @entity['link'].class.should == AppEngine::Datastore::Link
158
+ end
159
+
160
+ it "should support Time" do
161
+ time = Time.now - 3600
162
+ @entity['time'] = time
163
+ @entity['time'].to_s.should == time.to_s
164
+ @entity['time'].class.should == Time
165
+ end
166
+
167
+ it "should support multiple values" do
168
+ list = [1, 2, 3]
169
+ @entity['list'] = list
170
+ @entity['list'].should == list
171
+ end
172
+
173
+ it "should not support random types" do
174
+ lambda{@entity['foo'] = Kernel}.should raise_error(ArgumentError)
175
+ end
176
+
177
+ it "should support delete" do
178
+ @entity['foo'] = 'bar'
179
+ @entity.delete('foo')
180
+ @entity.has_property?('foo').should == false
181
+ end
182
+
183
+ it "should support delete symbol" do
184
+ @entity['foo'] = 'bar'
185
+ @entity.delete(:foo)
186
+ @entity.has_property?('foo').should == false
187
+ end
188
+
189
+ it "should support each" do
190
+ props = {'foo' => 'bar', 'count' => 3}
191
+ props.each {|name, value| @entity[name] = value}
192
+ @entity.each do |name, value|
193
+ props.delete(name).should == value
194
+ end
195
+ props.should == {}
196
+ end
197
+
198
+ end