rubyforge 0.0.0 → 1.0.4

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,400 @@
1
+ require 'test/unit' unless defined? $ZENTEST and $ZENTEST
2
+
3
+ $TESTING = true
4
+ require 'rubyforge'
5
+ require 'tmpdir'
6
+
7
+ class RubyForge
8
+ attr_writer :client
9
+
10
+ alias :old_save_autoconfig :save_autoconfig
11
+ def save_autoconfig
12
+ # raise "not during test"
13
+ end
14
+ end
15
+
16
+ class RubyForge::FakeClient
17
+ def form; end
18
+ def save_cookie_store(*args) end
19
+
20
+ def post_content(*args)
21
+ FakeRubyForge::HTML
22
+ end
23
+
24
+ def get_content(*args)
25
+ URI::HTTP.data.join("\n")
26
+ end
27
+ end
28
+
29
+ class FakeRubyForge < RubyForge
30
+ HTML = "blah blah <form action=\"/frs/admin/editrelease.php?group_id=440&release_id=6948&package_id=491\" method=\"post\"> blah blah"
31
+
32
+ attr_accessor :page, :form, :extheader, :requests, :scrape
33
+ def run(page, form, extheader={})
34
+ @page, @form, @extheader = page, form, extheader
35
+ @requests ||= []
36
+ @requests << { :url => page, :form => form, :headers => extheader }
37
+ HTML
38
+ end
39
+
40
+ def scrape_project(proj)
41
+ @scrape ||= []
42
+ @scrape << proj
43
+ end
44
+ end
45
+
46
+ # TODO: remove this and make rubyforge use Client exclusively
47
+ class URI::HTTP
48
+ def self.data
49
+ @data ||= []
50
+ end
51
+
52
+ def read
53
+ self.class.data.shift or raise "no more data"
54
+ end
55
+ end
56
+
57
+ class TestRubyForge < Test::Unit::TestCase
58
+ def setup
59
+ srand(0)
60
+ util_new FakeRubyForge
61
+ end
62
+
63
+ def teardown
64
+ File.unlink @cookie_path if defined? @cookie_path
65
+ # if defined? @old_autoconfig then
66
+ # @rubyforge.autoconfig.replace @old_autoconfig
67
+ # @rubyforge.save_autoconfig
68
+ # end
69
+ end
70
+
71
+ def test_new_with_proxy_uses_a_proxy_class
72
+ client = RubyForge::Client.new('http://localhost:8808/')
73
+ assert client.agent_class.proxy_class?, 'agent class should be a proxy'
74
+ end
75
+
76
+ def test_new_with_bad_proxy_uses_normal_http
77
+ client = RubyForge::Client.new('asdfkjhalksdfjh')
78
+ assert !client.agent_class.proxy_class?, 'agent class should not be a proxy'
79
+ end
80
+
81
+ def test_initialize_bad
82
+ @cookie_path = File.join(Dir.tmpdir, "cookie.#{$$}.dat")
83
+ File.open(@cookie_path, 'w') {} # touch
84
+
85
+ user_data = {
86
+ "uri" => "http://rubyforge.org",
87
+ "is_private" => false,
88
+ "cookie_jar" => @cookie_path,
89
+ "username" => "username",
90
+ "password" => "password"
91
+ }
92
+
93
+ assert_raise RuntimeError do
94
+ rf = RubyForge.new user_data
95
+ rf.configure "username" => nil
96
+ end
97
+ assert_raise RuntimeError do
98
+ rf = RubyForge.new user_data
99
+ rf.configure "password" => nil
100
+ end
101
+ assert_raise RuntimeError do
102
+ rf = RubyForge.new user_data
103
+ rf.configure "cookie_jar" => nil
104
+ end
105
+ end
106
+
107
+ def test_setup
108
+ # TODO raise NotImplementedError, 'Need to write test_setup'
109
+ end
110
+
111
+ def test_login
112
+ u, p = 'fooby', 's3kr3t'
113
+ @rubyforge.userconfig['username'] = u
114
+ @rubyforge.userconfig['password'] = p
115
+ @rubyforge.login
116
+
117
+ util_run('https://rubyforge.org/account/login.php',
118
+ 'form_pw' => p,
119
+ 'form_loginname' => u,
120
+ 'return_to' => '',
121
+ 'login' => 'Login')
122
+ end
123
+
124
+ def test_create_package
125
+ @rubyforge.create_package(42, 'woot_pkg')
126
+
127
+ util_run('/frs/admin/index.php',
128
+ "submit" => "Create This Package",
129
+ "group_id" => 42,
130
+ "is_public" => 1,
131
+ "package_name" => "woot_pkg",
132
+ "func" => "add_package")
133
+ end
134
+
135
+ def test_delete_package
136
+ @rubyforge.delete_package(42, 666)
137
+ util_delete_package
138
+ end
139
+
140
+ def test_delete_package_package_name
141
+ @rubyforge.delete_package(42, "woot_pkg")
142
+ util_delete_package
143
+ end
144
+
145
+ def test_delete_package_undefined_package_name
146
+ assert_raise RuntimeError do
147
+ @rubyforge.delete_package(42, "blah")
148
+ end
149
+ end
150
+
151
+ def test_delete_package_group_name
152
+ @rubyforge.delete_package("seattlerb", 666)
153
+ util_delete_package
154
+ end
155
+
156
+ def test_delete_package_undefined_group_name
157
+ assert_raise RuntimeError do
158
+ @rubyforge.delete_package("blah", 666)
159
+ end
160
+ end
161
+
162
+ def test_add_file
163
+ @rubyforge.autoconfig["package_ids"]["ringy_dingy"] = 314
164
+ @rubyforge.autoconfig["release_ids"]["ringy_dingy"] ||= {}
165
+ @rubyforge.autoconfig["release_ids"]["ringy_dingy"]["1.2.3"] = 43
166
+
167
+ @rubyforge.add_file('seattlerb', 'ringy_dingy', '1.2.3', __FILE__)
168
+
169
+ util_run('/frs/admin/editrelease.php?group_id=42&release_id=43&package_id=314',
170
+ { "step2" => 1,
171
+ "type_id" => 9999,
172
+ "processor_id" => 8000,
173
+ "submit" => "Add This File"},
174
+ {"content-type"=> "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"})
175
+ end
176
+
177
+ def test_add_release
178
+ @rubyforge.add_release(42, 666, '1.2.3', __FILE__)
179
+ util_add_release
180
+ end
181
+
182
+ def test_add_release_multiple
183
+ @rubyforge.add_release(42, 666, '1.2.3', __FILE__, __FILE__) # dunno if that'll work
184
+ add_release = ({ :url=>"/frs/admin/qrs.php",
185
+ :form=>{"processor_id"=>8000,
186
+ "submit"=>"Release File",
187
+ "preformatted"=>0,
188
+ "release_changes"=>nil,
189
+ "type_id"=>9999,
190
+ "group_id"=>42,
191
+ "release_name"=>"1.2.3",
192
+ "release_notes"=>nil,
193
+ "package_id"=>666,
194
+ "release_date"=>"today"},
195
+ :headers=> {"content-type" => "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"}})
196
+ add_file = ({ :url => '/frs/admin/editrelease.php?group_id=42&release_id=6948&package_id=666',
197
+ :form => { "step2" => 1,
198
+ "type_id" => 9999,
199
+ "processor_id" => 8000,
200
+ "submit" => "Add This File"},
201
+ :headers => {"content-type"=> "multipart/form-data; boundary=___23__06__24__24__12__01__38__39___"}})
202
+ expected = [add_release, add_file]
203
+
204
+ result = @rubyforge.requests
205
+ result.each do |r|
206
+ r[:form].delete "userfile"
207
+ end
208
+
209
+ assert_equal expected, result
210
+ end
211
+
212
+ def test_post_news
213
+ @rubyforge.post_news("seattlerb", "my summary", "my news")
214
+
215
+ util_run("/news/submit.php",
216
+ "group_id" => 42,
217
+ "post_changes" => "y",
218
+ "details" => "my news",
219
+ "summary" => "my summary",
220
+ "submit" => "Submit")
221
+ end
222
+
223
+ def test_add_release_package_name
224
+ @rubyforge.add_release(42, "woot_pkg", '1.2.3', __FILE__)
225
+ util_add_release
226
+ end
227
+
228
+ def test_add_release_undefined_package_name
229
+ assert_raise RuntimeError do
230
+ @rubyforge.add_release(42, "blah", '1.2.3', __FILE__)
231
+ end
232
+ end
233
+
234
+ def test_add_release_group_name
235
+ @rubyforge.add_release("seattlerb", 666, '1.2.3', __FILE__)
236
+ util_add_release
237
+ end
238
+
239
+ def test_add_release_undefined_group_name
240
+ assert_raise RuntimeError do
241
+ @rubyforge.add_release("blah", 666, '1.2.3', __FILE__)
242
+ end
243
+ end
244
+
245
+ def test_lookup_id
246
+ assert_equal 43, @rubyforge.lookup("package", 43)
247
+ end
248
+
249
+ def test_lookup_string_number
250
+ assert_raise RuntimeError do
251
+ @rubyforge.lookup("package", "43")
252
+ end
253
+ end
254
+
255
+ def test_lookup_name
256
+ @rubyforge.autoconfig["package_ids"]["ringy_dingy"] = 314
257
+ assert_equal 314, @rubyforge.lookup("package", "ringy_dingy")
258
+ end
259
+
260
+ def test_lookup_undefined
261
+ assert_raise RuntimeError do
262
+ @rubyforge.lookup("package", "blah")
263
+ end
264
+ end
265
+
266
+ def test_run
267
+ util_new FakeRubyForge
268
+ result = @rubyforge.add_release(42, 666, '1.2.3', __FILE__)
269
+
270
+ assert_equal 6948, result
271
+ extheader = {"content-type"=> "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"}
272
+
273
+ form = {
274
+ "processor_id" => 8000,
275
+ "submit" => "Release File",
276
+ "preformatted" => 0,
277
+ "release_changes" => nil,
278
+ "type_id" => 9999,
279
+ "group_id" => 42,
280
+ "release_name" => "1.2.3",
281
+ "release_notes" => nil,
282
+ "package_id" => 666,
283
+ "release_date" => "today"
284
+ }
285
+
286
+ client = @rubyforge.client
287
+ # assert client.form.delete("userfile")
288
+
289
+ # assert_equal 'http://rubyforge.org/frs/admin/qrs.php', client.url.to_s
290
+ # assert_equal form, client.form
291
+ # assert_equal extheader, client.headers
292
+ end
293
+
294
+ def test_scrape_project
295
+ orig_stdout = $stdout
296
+ orig_stderr = $stderr
297
+ $stdout = StringIO.new
298
+ $stderr = StringIO.new
299
+ util_new RubyForge # TODO: switch to Fake
300
+ @rubyforge.autoconfig.each { |k,v| v.clear }
301
+
302
+ URI::HTTP.data << "<a href='/tracker/?group_id=1513'>Tracker</a>"
303
+ URI::HTTP.data << <<-EOF
304
+ <h3>ar_mailer
305
+ <a href="/frs/monitor.php?filemodule_id=4566&group_id=1513&start=1">
306
+ <a href="shownotes.php?release_id=13368">1.3.1</a>
307
+ <a href="shownotes.php?release_id=12185">1.2.0</a></strong>
308
+ EOF
309
+
310
+ # @rubyforge.scrape << < <-EOF
311
+ URI::HTTP.data << <<-EOF
312
+ <select name="processor_id">
313
+ <option value="100">Must Choose One</option>
314
+ <option value="1000">i386</option>
315
+ <option value="1001">i387</option>
316
+ </select>
317
+ EOF
318
+
319
+ @rubyforge.scrape_project('my_project')
320
+
321
+ expected = {
322
+ "group_ids" => { "my_project" => 1513 },
323
+ "package_ids" => { "ar_mailer" => 4566 },
324
+ "processor_ids" => { "i386" => 1000, "i387" => 1001 },
325
+ "release_ids" => {
326
+ "ar_mailer" => { "1.2.0" => 12185, "1.3.1" => 13368 }
327
+ },
328
+ "type_ids" => {},
329
+ }
330
+
331
+ assert_equal expected, @rubyforge.autoconfig
332
+ ensure
333
+ $stdout = orig_stdout
334
+ $stderr = orig_stderr
335
+ end
336
+
337
+ def util_new(klass)
338
+ @cookie_path = File.join(Dir.tmpdir, "cookie.#{$$}.dat")
339
+ File.open(@cookie_path, 'w') {} # touch
340
+
341
+ user_data = {
342
+ "uri" => "http://rubyforge.org",
343
+ "is_private" => false,
344
+ "cookie_jar" => @cookie_path,
345
+ "username" => "username",
346
+ "password" => "password"
347
+ }
348
+
349
+ auto_data = {
350
+ "group_ids" => {},
351
+ "package_ids" => {},
352
+ "release_ids" => Hash.new { |h,k| h[k] = {} },
353
+ "type_ids" => {},
354
+ "processor_ids" => {"Any"=>8000},
355
+ }
356
+
357
+ @rubyforge = klass.new user_data, auto_data
358
+
359
+ @rubyforge.client = RubyForge::FakeClient.new
360
+
361
+ @rubyforge.userconfig["release_date"] = "today"
362
+ @rubyforge.autoconfig["type_ids"][".rb"] = 9999
363
+ @rubyforge.autoconfig["group_ids"]["seattlerb"] = 42
364
+ @rubyforge.autoconfig["package_ids"]["woot_pkg"] = 666
365
+ end
366
+
367
+ def util_run(page, form={}, extheader={})
368
+ form_result = @rubyforge.form
369
+ assert form_result.delete("userfile") unless extheader.empty?
370
+
371
+ assert_equal page, @rubyforge.page.to_s
372
+ assert_equal form, form_result
373
+ assert_equal extheader, @rubyforge.extheader
374
+ end
375
+
376
+ def util_add_release
377
+ util_run('/frs/admin/qrs.php',
378
+ {"processor_id" => 8000,
379
+ "submit" => "Release File",
380
+ "preformatted" => 0,
381
+ "release_changes" => nil,
382
+ "type_id" => 9999,
383
+ "group_id" => 42,
384
+ "release_name" => "1.2.3",
385
+ "release_notes" => nil,
386
+ "package_id" => 666,
387
+ "release_date" => "today"},
388
+ {"content-type"=> "multipart/form-data; boundary=___00__03__03__39__09__19__21__36___"})
389
+ end
390
+
391
+ def util_delete_package
392
+ util_run('/frs/admin/index.php',
393
+ "submit" => "Delete",
394
+ "really_sure" => "1",
395
+ "group_id" => 42,
396
+ "func" => "delete_package",
397
+ "package_id" => 666,
398
+ "sure" => "1")
399
+ end
400
+ end
@@ -0,0 +1,122 @@
1
+ require 'test/unit' unless defined? $ZENTEST and $ZENTEST
2
+ require 'rubyforge'
3
+
4
+ class RubyForge::FakeAgent
5
+ class << self
6
+ attr_accessor :t_data, :t_request
7
+ end
8
+
9
+ def initialize(*args)
10
+ end
11
+
12
+ def request(request, data)
13
+ self.class.t_request = request
14
+ self.class.t_data = data
15
+ response = Net::HTTPOK.new('1.1', 200, '')
16
+ def response.read_body; ''; end
17
+ return response
18
+ end
19
+
20
+ class Post
21
+ def initialize(*args)
22
+ @args = args
23
+ @stuff = {}
24
+ end
25
+
26
+ def [] key
27
+ @stuff[key.downcase]
28
+ end
29
+
30
+ def []= key, val
31
+ @stuff[key.downcase] = val
32
+ end
33
+
34
+ def method_missing(*stuff)
35
+ # warn stuff.inspect
36
+ end
37
+ end
38
+ end
39
+
40
+ class TestRubyForgeClient < Test::Unit::TestCase
41
+ def setup
42
+ @client = RubyForge::Client.new
43
+ @client.agent_class = RubyForge::FakeAgent
44
+ RubyForge::FakeAgent.t_data = :unassigned
45
+ RubyForge::FakeAgent.t_request = :unassigned
46
+ end
47
+
48
+ def test_post_with_params
49
+ @client.post_content('http://example.com', { :f => 'adsf aoeu'})
50
+ assert_equal('f=adsf+aoeu', RubyForge::FakeAgent.t_data)
51
+
52
+ @client.post_content('http://example.com', { :a => 'b', :c => 'd' })
53
+ assert_equal('a=b&c=d', RubyForge::FakeAgent.t_data)
54
+ end
55
+
56
+ def test_multipart_post_one_param
57
+ random = Array::new(8){ "%2.2d" % rand(42) }.join('__')
58
+ boundary = "multipart/form-data; boundary=___#{ random }___"
59
+
60
+ expected = <<-END
61
+ --___#{random}___\r
62
+ Content-Disposition: form-data; name="a"\r\n\r
63
+ a b c\r
64
+ --___#{random}___--\r
65
+ END
66
+
67
+ @client.post_content( 'http://example.com',
68
+ { :a => 'a b c' },
69
+ { 'content-type' => boundary }
70
+ )
71
+ assert_equal(expected, RubyForge::FakeAgent.t_data)
72
+ end
73
+
74
+ def test_multipart_post_two_params
75
+ random = Array::new(8){ "%2.2d" % rand(42) }.join('__')
76
+ boundary = "multipart/form-data; boundary=___#{ random }___"
77
+
78
+ request = <<-END
79
+ --___#{random}___\r
80
+ Content-Disposition: form-data; name="a"\r\n\r
81
+ b\r
82
+ --___#{random}___\r
83
+ Content-Disposition: form-data; name="c"\r\n\r
84
+ d\r
85
+ --___#{random}___--\r
86
+ END
87
+
88
+ @client.post_content( 'http://example.com',
89
+ { :a => 'b', :c => 'd' },
90
+ { 'content-type' => boundary }
91
+ )
92
+ assert_equal(request, RubyForge::FakeAgent.t_data)
93
+ end
94
+
95
+ def test_multipart_io
96
+ random = Array::new(8){ "%2.2d" % rand(42) }.join('__')
97
+ boundary = "multipart/form-data; boundary=___#{ random }___"
98
+
99
+ file_contents = 'blah blah blah'
100
+ file = StringIO.new(file_contents)
101
+ class << file
102
+ def path
103
+ '/one/two/three.rb'
104
+ end
105
+ end
106
+
107
+ request = <<-END
108
+ --___#{random}___\r
109
+ Content-Disposition: form-data; name="userfile"; filename="three.rb"\r
110
+ Content-Transfer-Encoding: binary\r
111
+ Content-Type: text/plain\r\n\r
112
+ #{file_contents}\r
113
+ --___#{random}___--\r
114
+ END
115
+
116
+ @client.post_content( 'http://example.com',
117
+ { :userfile => file },
118
+ { 'content-type' => boundary }
119
+ )
120
+ assert_equal(request, RubyForge::FakeAgent.t_data)
121
+ end
122
+ end
@@ -0,0 +1,97 @@
1
+ require 'test/unit' unless defined? $ZENTEST and $ZENTEST
2
+ require 'rubyforge'
3
+ require 'time'
4
+ require 'yaml'
5
+ require 'tempfile'
6
+
7
+ class TestRubyForgeCookieManager < Test::Unit::TestCase
8
+ def setup
9
+ cookie = cookie_string('session_ser', 'zzzzzzzzzzzzzzzzzz')
10
+ @url = URI.parse('http://rubyforge.org/account/login.php')
11
+ @cookie = WEBrick::Cookie.parse_set_cookie(cookie)
12
+ @manager = RubyForge::CookieManager.new
13
+ end
14
+
15
+ def test_empty?
16
+ manager = RubyForge::CookieManager.new
17
+ assert(manager.empty?)
18
+
19
+ assert_equal(0, manager[URI.parse('http://rubyforge.org/')].length)
20
+ assert(manager.empty?)
21
+ end
22
+
23
+ def test_add
24
+ manager = RubyForge::CookieManager.new
25
+ assert(manager.empty?)
26
+ manager.add(@url, @cookie)
27
+ assert(!manager.empty?)
28
+
29
+ cookie = manager[@url][@cookie.name]
30
+ assert cookie
31
+ assert_equal(@cookie.object_id, cookie.object_id)
32
+ end
33
+
34
+ def test_add_expired_cookie
35
+ cookie = cookie_string('session_ser', 'zzzz',
36
+ :expires => (Time.now - 10).strftime('%A, %d-%b-%Y %H:%M:%S %Z'))
37
+ cookie = WEBrick::Cookie.parse_set_cookie(cookie)
38
+
39
+ manager = RubyForge::CookieManager.new
40
+ assert(manager.empty?)
41
+ manager.add(@url, cookie)
42
+ assert(manager.empty?)
43
+ end
44
+
45
+ def test_marshal
46
+ @manager.add(@url, @cookie)
47
+ assert(!@manager.empty?)
48
+ m = YAML.load(YAML.dump(@manager))
49
+ assert(!m.empty?)
50
+ end
51
+
52
+ def test_save!
53
+ tmp = Tempfile.new('cookie_jar')
54
+ @manager.cookies_file = tmp.path
55
+ @manager.add(@url, @cookie)
56
+ @manager.save!
57
+
58
+ @manager = RubyForge::CookieManager.load(tmp.path)
59
+ assert(! @manager.empty?)
60
+ end
61
+
62
+ def test_load_empty_file
63
+ tmp = Tempfile.new('cookie_jar')
64
+ manager = RubyForge::CookieManager.load(tmp.path)
65
+ assert(manager.empty?)
66
+ end
67
+
68
+ def test_load_legacy_file
69
+ tmp = Tempfile.new('cookie_jar')
70
+ tmp.write([
71
+ 'https://rubyforge.org/account/login.php',
72
+ 'session_ser',
73
+ 'zzzzzz',
74
+ '123456',
75
+ '.rubyforge.org',
76
+ '/',
77
+ '13'
78
+ ].join("\t"))
79
+ manager = RubyForge::CookieManager.load(tmp.path)
80
+ assert(manager.empty?)
81
+ end
82
+
83
+ def test_cookies_file=
84
+ tmp = Tempfile.new('cookie_jar')
85
+ @manager.cookies_file = tmp.path
86
+ assert(@manager.empty?)
87
+ end
88
+
89
+ def cookie_string(name, value, options = {})
90
+ options = {
91
+ :expires => (Time.now + 86400).strftime('%A, %d-%b-%Y %H:%M:%S %Z'),
92
+ :path => '/',
93
+ :domain => '.rubyforge.org',
94
+ }.merge(options)
95
+ "#{name}=#{value}; #{options.map { |o| o.join('=') }.join('; ')}"
96
+ end
97
+ end