impostor 0.2.1 → 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.gemtest +0 -0
- data/.gitignore +1 -0
- data/.rspec +2 -0
- data/.rvmrc +1 -0
- data/Gemfile +17 -0
- data/Gemfile.lock +47 -0
- data/History.txt +8 -0
- data/Manifest.txt +87 -55
- data/README.txt +11 -11
- data/Rakefile +16 -20
- data/lib/impostor/auth.rb +103 -0
- data/lib/impostor/config.rb +171 -0
- data/lib/impostor/errors.rb +67 -0
- data/lib/impostor/phpbb2.rb +202 -0
- data/lib/impostor/phpbb3.rb +199 -0
- data/lib/impostor/post.rb +111 -0
- data/lib/impostor/topic.rb +115 -0
- data/lib/impostor/wwf79.rb +186 -0
- data/lib/impostor/wwf80.rb +190 -0
- data/lib/impostor.rb +108 -5
- data/spec/auth_spec.rb +148 -0
- data/spec/base_spec_helper.rb +12 -0
- data/{test/test_helper.rb → spec/caged_net_http.rb} +8 -17
- data/spec/config_spec.rb +136 -0
- data/spec/fixtures/junk.html +1 -0
- data/{test → spec}/fixtures/phpbb2-get-new_topic-form-good-response.html +0 -0
- data/{test → spec}/fixtures/phpbb2-get-viewtopic-for-new-topic-good-response.html +11 -11
- data/{test → spec}/fixtures/phpbb2-get-viewtopic-for-new-topic-malformed-response.html +0 -0
- data/{test → spec}/fixtures/phpbb2-index.html +0 -0
- data/{test → spec}/fixtures/phpbb2-logged-in.html +0 -0
- data/{test → spec}/fixtures/phpbb2-login.html +0 -0
- data/{test → spec}/fixtures/phpbb2-not-logged-in.html +0 -0
- data/{test → spec}/fixtures/phpbb2-post-new_topic-good-response.html +0 -0
- data/{test → spec}/fixtures/phpbb2-post-reply-good-response.html +0 -0
- data/{test → spec}/fixtures/phpbb2-post-reply-throttled-response.html +0 -0
- data/{test → spec}/fixtures/phpbb2-too-many-posts.html +0 -0
- data/{test → spec}/fixtures/phpbb3-get-new-topic-form-good-response.html +0 -0
- data/{test → spec}/fixtures/phpbb3-get-reply-form-good-response.html +0 -0
- data/{test → spec}/fixtures/phpbb3-logged-in.html +0 -0
- data/{test → spec}/fixtures/phpbb3-login.html +0 -0
- data/{test → spec}/fixtures/phpbb3-not-logged-in.html +0 -0
- data/{test → spec}/fixtures/phpbb3-post-new_topic-good-response.html +0 -0
- data/{test → spec}/fixtures/phpbb3-post-reply-good-response.html +0 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-be-overlimit-creating-topic.yml +1308 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-create-topic.yml +923 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-login.yml +360 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-not-create-new-topic.yml +497 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-not-login.yml +287 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-not-post.yml +497 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-overlimit-error-post.yml +1140 -0
- data/spec/fixtures/vcr_cassettes/phpbb2-should-post.yml +751 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-be-overlimit-creating-topic.yml +995 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-create-topic.yml +675 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-login.yml +245 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-not-create-new-topic.yml +350 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-not-login.yml +253 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-not-post.yml +350 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-overlimit-error-post.yml +1046 -0
- data/spec/fixtures/vcr_cassettes/phpbb3-should-post.yml +605 -0
- data/{test → spec}/fixtures/wwf79-forum_posts.html +0 -0
- data/{test → spec}/fixtures/wwf79-general-new-topic-error.html +0 -0
- data/{test → spec}/fixtures/wwf79-general-posting-error.html +0 -0
- data/{test → spec}/fixtures/wwf79-good-post-forum_posts.html +1 -1
- data/{test → spec}/fixtures/wwf79-index.html +0 -0
- data/{test → spec}/fixtures/wwf79-logged-in.html +0 -0
- data/{test → spec}/fixtures/wwf79-login.html +0 -0
- data/{test → spec}/fixtures/wwf79-new-topic-forum_posts-response.html +0 -0
- data/{test → spec}/fixtures/wwf79-new-topic-post_message_form.html +0 -0
- data/{test → spec}/fixtures/wwf79-not-logged-in.html +0 -0
- data/{test → spec}/fixtures/wwf79-too-many-posts.html +0 -0
- data/{test → spec}/fixtures/wwf79-too-many-topics.html +0 -0
- data/{test → spec}/fixtures/wwf80-general-posting-error.html +0 -0
- data/{test → spec}/fixtures/wwf80-get-new_topic-form-good-response.html +0 -0
- data/{test → spec}/fixtures/wwf80-get-viewtopic-for-new-topic-good-response.html +0 -0
- data/{test → spec}/fixtures/wwf80-index.html +0 -0
- data/{test → spec}/fixtures/wwf80-logged-in.html +0 -0
- data/{test → spec}/fixtures/wwf80-login.html +0 -0
- data/{test → spec}/fixtures/wwf80-new_reply_form.html +0 -0
- data/{test → spec}/fixtures/wwf80-not-logged-in.html +0 -0
- data/{test → spec}/fixtures/wwf80-post-new_topic-good-response.html +1 -1
- data/{test → spec}/fixtures/wwf80-post-reply-good-response.html +0 -0
- data/{test → spec}/fixtures/wwf80-too-many-posts.html +0 -0
- data/spec/impostor_spec_helper.rb +162 -0
- data/spec/integration/phpbb2_spec.rb +111 -0
- data/spec/integration/phpbb3_spec.rb +109 -0
- data/spec/integration_spec_helper.rb +7 -0
- data/spec/phpbb2_spec.rb +346 -0
- data/spec/phpbb3_spec.rb +332 -0
- data/spec/post_spec.rb +134 -0
- data/spec/spec_helper.rb +2 -0
- data/spec/test_impostor.rb +12 -0
- data/spec/topic_spec.rb +143 -0
- data/spec/wwf79_spec.rb +342 -0
- data/spec/wwf80_spec.rb +339 -0
- metadata +156 -87
- data/lib/www/impostor/phpbb2.rb +0 -258
- data/lib/www/impostor/phpbb3.rb +0 -236
- data/lib/www/impostor/wwf79.rb +0 -254
- data/lib/www/impostor/wwf80.rb +0 -264
- data/lib/www/impostor.rb +0 -269
- data/test/test_github.rb +0 -12
- data/test/test_www_impostor.rb +0 -165
- data/test/test_www_impostor_phpbb2.rb +0 -536
- data/test/test_www_impostor_phpbb3.rb +0 -483
- data/test/test_www_impostor_wwf79.rb +0 -535
- data/test/test_www_impostor_wwf80.rb +0 -535
- data/vendor/plugins/impostor/lib/autotest/discover.rb +0 -3
- data/vendor/plugins/impostor/lib/autotest/impostor.rb +0 -49
@@ -0,0 +1,186 @@
|
|
1
|
+
##
|
2
|
+
# Web Wiz Forums version 7.9 of the Impostor
|
3
|
+
#
|
4
|
+
|
5
|
+
class Impostor
|
6
|
+
|
7
|
+
module Wwf79
|
8
|
+
|
9
|
+
##
|
10
|
+
# Additional configuration parameters for a Wwf79 compatible agent:
|
11
|
+
#
|
12
|
+
# :forum_posts_page
|
13
|
+
# :post_message_page
|
14
|
+
#
|
15
|
+
# Typical configuration parameters
|
16
|
+
# { :type => :wwf79,
|
17
|
+
# :app_root => 'http://example.com/forum/',
|
18
|
+
# :login_page => 'login_user.asp',
|
19
|
+
# :forum_posts_page => 'forum_posts.asp',
|
20
|
+
# :post_message_page => 'post_message_form.asp'
|
21
|
+
# :user_agent => 'Windows IE 7',
|
22
|
+
# :username => 'myuser',
|
23
|
+
# :password => 'mypasswd' }
|
24
|
+
|
25
|
+
module Auth
|
26
|
+
|
27
|
+
def login # :nodoc:
|
28
|
+
Impostor.not_tested("Impostor::Wwf79::Auth", "login")
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# Checks if the agent is already logged by stored cookie
|
34
|
+
|
35
|
+
def logged_in?(page)
|
36
|
+
mm = page.search("//a[@class='nav']")
|
37
|
+
!! mm.detect { |m| m.text =~ /Logout \[#{self.config.username}\]/ }
|
38
|
+
end
|
39
|
+
|
40
|
+
##
|
41
|
+
# returns the login form from the login page
|
42
|
+
|
43
|
+
def get_login_form(page)
|
44
|
+
form = page.form('frmLogin')
|
45
|
+
raise Impostor::LoginError.new("unknown login page format") unless form
|
46
|
+
form
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# Sets the user name and pass word on the loing form.
|
51
|
+
def set_username_and_password(form)
|
52
|
+
button = Mechanize::Form::Button.new('Submit', 'Forum Login')
|
53
|
+
form.add_button_to_query(button)
|
54
|
+
form['name'] = self.config.username
|
55
|
+
form['password'] = self.config.password
|
56
|
+
form
|
57
|
+
end
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
module Post
|
62
|
+
|
63
|
+
def post(forum, topic, message) # :nodoc:
|
64
|
+
Impostor.not_tested("Impostor::Wwf79::Post", "post")
|
65
|
+
super
|
66
|
+
end
|
67
|
+
|
68
|
+
##
|
69
|
+
# return a uri used to fetch the reply page based on the forum, topic, and
|
70
|
+
# message
|
71
|
+
|
72
|
+
def get_reply_uri(forum, topic)
|
73
|
+
uri = URI.join(self.config.app_root, self.config.config(:forum_posts_page))
|
74
|
+
uri.query = "TID=#{topic}&TPN=10000"
|
75
|
+
uri
|
76
|
+
end
|
77
|
+
|
78
|
+
##
|
79
|
+
# return the form used for posting a message from the reply page
|
80
|
+
|
81
|
+
def get_post_form(page)
|
82
|
+
form = page.form('frmAddMessage')
|
83
|
+
raise Impostor::PostError.new("unknown reply page format") unless form
|
84
|
+
form
|
85
|
+
end
|
86
|
+
|
87
|
+
##
|
88
|
+
# get post id from the result of posting the message form
|
89
|
+
# FIXME this validation is copied into topic module as well
|
90
|
+
|
91
|
+
def get_post_from_result(page)
|
92
|
+
error = page.body =~ /Message Not Posted/
|
93
|
+
if error
|
94
|
+
|
95
|
+
# throttled
|
96
|
+
throttled = "You have exceeded the number of posts permitted in the time span"
|
97
|
+
too_many = page.body =~ /#{throttled}/
|
98
|
+
raise Impostor::ThrottledError.new(throttled) if too_many
|
99
|
+
|
100
|
+
# general error
|
101
|
+
raise Impostor::PostError.new("There was an error making the post")
|
102
|
+
end
|
103
|
+
|
104
|
+
kv = page.links.collect{ |l| l.uri }.compact.
|
105
|
+
collect{ |l| l.query }.compact.
|
106
|
+
collect{ |q| q.split('&')}.flatten.
|
107
|
+
detect{|kv| kv =~ /^PID=/ }
|
108
|
+
postid = URI.unescape(kv).split('#').first.split('=').last.to_i
|
109
|
+
raise Impostor::PostError.new("Message did not post.") if postid.zero?
|
110
|
+
postid
|
111
|
+
end
|
112
|
+
|
113
|
+
end
|
114
|
+
|
115
|
+
module Topic
|
116
|
+
|
117
|
+
def new_topic(forum, subject, message) # :nodoc:
|
118
|
+
Impostor.not_tested("Impostor::Wwf79::Topic", "new_topic")
|
119
|
+
super
|
120
|
+
end
|
121
|
+
|
122
|
+
##
|
123
|
+
# return a uri used to fetch the new topic page based on the forum, subject,
|
124
|
+
# and message
|
125
|
+
|
126
|
+
def get_new_topic_uri(forum, subject, message)
|
127
|
+
uri = URI.join(self.config.app_root, self.config.config(:post_message_page))
|
128
|
+
uri.query = "FID=#{forum}"
|
129
|
+
uri
|
130
|
+
end
|
131
|
+
|
132
|
+
##
|
133
|
+
# Get the the new topic form on the page
|
134
|
+
|
135
|
+
def get_new_topic_form(page)
|
136
|
+
form = page.form('frmAddMessage')
|
137
|
+
raise Impostor::TopicError.new("unknown new topic page format") unless form
|
138
|
+
form
|
139
|
+
end
|
140
|
+
|
141
|
+
##
|
142
|
+
# Set the subject and message on the new topic form
|
143
|
+
|
144
|
+
def set_subject_and_message(form, subject, message)
|
145
|
+
form.subject = subject
|
146
|
+
form.message = message
|
147
|
+
form
|
148
|
+
end
|
149
|
+
|
150
|
+
##
|
151
|
+
# validate the result of posting the message form
|
152
|
+
# FIXME this validation is copied into post module as well
|
153
|
+
|
154
|
+
def validate_new_topic_result(page)
|
155
|
+
error = page.body =~ /Message Not Posted/
|
156
|
+
if error
|
157
|
+
|
158
|
+
# throttled
|
159
|
+
throttled = "You have exceeded the number of posts permitted in the time span"
|
160
|
+
too_many = page.body =~ /#{throttled}/
|
161
|
+
raise Impostor::ThrottledError.new(throttled) if too_many
|
162
|
+
|
163
|
+
# general error
|
164
|
+
raise Impostor::TopicError.new("There was an error making the post")
|
165
|
+
end
|
166
|
+
|
167
|
+
page
|
168
|
+
end
|
169
|
+
|
170
|
+
##
|
171
|
+
# Get the new topic identifier from the result page
|
172
|
+
|
173
|
+
def get_topic_from_result(page)
|
174
|
+
begin
|
175
|
+
tid = page.form('frmAddMessage')['TID'].to_i
|
176
|
+
raise StandardError.new("new topic id not found") if tid.zero?
|
177
|
+
tid
|
178
|
+
rescue StandardError => err
|
179
|
+
raise Impostor::TopicError.new(err)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
end
|
184
|
+
|
185
|
+
end
|
186
|
+
end
|
@@ -0,0 +1,190 @@
|
|
1
|
+
##
|
2
|
+
# Web Wiz Forums version 8.0 of the Impostor
|
3
|
+
#
|
4
|
+
|
5
|
+
class Impostor
|
6
|
+
|
7
|
+
module Wwf80
|
8
|
+
|
9
|
+
##
|
10
|
+
# Additional configuration parameters for a Wwf80 compatible agent:
|
11
|
+
#
|
12
|
+
# :new_reply_page
|
13
|
+
# :new_topic_page
|
14
|
+
#
|
15
|
+
# Typical configuration parameters
|
16
|
+
# { :type => :wwf80,
|
17
|
+
# :app_root => 'http://example.com/forum/',
|
18
|
+
# :login_page => 'login_user.asp',
|
19
|
+
# :new_reply_page => 'new_reply_form.asp',
|
20
|
+
# :new_topic_page => 'new_topic_form.asp',
|
21
|
+
# :user_agent => 'Windows IE 7',
|
22
|
+
# :username => 'myuser',
|
23
|
+
# :password => 'mypasswd' }
|
24
|
+
|
25
|
+
module Auth
|
26
|
+
|
27
|
+
def login # :nodoc:
|
28
|
+
Impostor.not_tested("Impostor::Wwf80::Auth", "login")
|
29
|
+
super
|
30
|
+
end
|
31
|
+
|
32
|
+
##
|
33
|
+
# returns the login form from the login page
|
34
|
+
|
35
|
+
def get_login_form(page)
|
36
|
+
form = page.form('frmLogin')
|
37
|
+
raise Impostor::LoginError.new("unknown login page format") unless form
|
38
|
+
form
|
39
|
+
end
|
40
|
+
|
41
|
+
##
|
42
|
+
# Sets the user name and pass word on the loing form.
|
43
|
+
def set_username_and_password(form)
|
44
|
+
form['name'] = self.config.username
|
45
|
+
form['password'] = self.config.password
|
46
|
+
form
|
47
|
+
end
|
48
|
+
|
49
|
+
##
|
50
|
+
# given the state of the page, are we logged in to the forum?
|
51
|
+
|
52
|
+
def logged_in?(page)
|
53
|
+
mm = page.search("//a[@class='nav']")
|
54
|
+
!! mm.detect { |m| m.text =~ /Logout \[#{self.config.username}\]/ }
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
|
59
|
+
module Post
|
60
|
+
|
61
|
+
def post(forum, topic, message) # :nodoc:
|
62
|
+
Impostor.not_tested("Impostor::Wwf80::Post", "post")
|
63
|
+
super
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# return a uri used to fetch the reply page based on the forum, topic, and
|
68
|
+
# message
|
69
|
+
|
70
|
+
def get_reply_uri(forum, topic)
|
71
|
+
uri = URI.join(self.config.app_root, self.config.config(:new_reply_page))
|
72
|
+
uri.query = "TID=#{topic}"
|
73
|
+
uri
|
74
|
+
end
|
75
|
+
|
76
|
+
##
|
77
|
+
# return the form used for posting a message from the reply page
|
78
|
+
|
79
|
+
def get_post_form(page)
|
80
|
+
form = page.form('frmMessageForm')
|
81
|
+
raise Impostor::PostError.new("unknown reply page format") unless form
|
82
|
+
form
|
83
|
+
end
|
84
|
+
|
85
|
+
##
|
86
|
+
# get post id from the result of posting the message form
|
87
|
+
# FIXME this validation is copied into topic module as well
|
88
|
+
|
89
|
+
def get_post_from_result(page)
|
90
|
+
error = page.search("//table[@class='errorTable']")
|
91
|
+
if error
|
92
|
+
msgs = error.search("//td")
|
93
|
+
|
94
|
+
# throttled
|
95
|
+
too_many = msgs.last && msgs.last.text && msgs.last.text =~ /You have exceeded the number of posts permitted in the time span/
|
96
|
+
raise ThrottledError.new(msgs.last.text.gsub(/\s+/m,' ').strip) if too_many
|
97
|
+
|
98
|
+
# general error
|
99
|
+
had_error = error.last && error.last.text && error.last.text =~ /Error: Message Not Posted/
|
100
|
+
raise Impostor::PostError.new(error.last.text.gsub(/\s+/m,' ').strip) if had_error
|
101
|
+
end
|
102
|
+
|
103
|
+
kv = page.links.collect{ |l| l.uri }.compact.
|
104
|
+
collect{ |l| l.query }.compact.
|
105
|
+
collect{ |q| q.split('&')}.flatten.
|
106
|
+
detect{|kv| kv =~ /^PID=/ }
|
107
|
+
postid = URI.unescape(kv).split('#').first.split('=').last.to_i
|
108
|
+
raise Impostor::PostError.new("Message did not post.") if postid.zero?
|
109
|
+
postid
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
113
|
+
|
114
|
+
module Topic
|
115
|
+
|
116
|
+
def new_topic(forum, subject, message) # :nodoc:
|
117
|
+
Impostor.not_tested("Impostor::Wwf80::Topic", "new_topic")
|
118
|
+
super
|
119
|
+
end
|
120
|
+
|
121
|
+
##
|
122
|
+
# return a uri used to fetch the new topic page based on the forum, subject,
|
123
|
+
# and message
|
124
|
+
|
125
|
+
def get_new_topic_uri(forum, subject, message)
|
126
|
+
uri = URI.join(self.config.app_root, self.config.config(:new_topic_page))
|
127
|
+
uri.query = "FID=#{forum}"
|
128
|
+
uri
|
129
|
+
end
|
130
|
+
|
131
|
+
##
|
132
|
+
# Get the the new topic form on the page
|
133
|
+
|
134
|
+
def get_new_topic_form(page)
|
135
|
+
form = page.form('frmMessageForm')
|
136
|
+
raise Impostor::TopicError.new("unknown new topic page format") unless form
|
137
|
+
form
|
138
|
+
end
|
139
|
+
|
140
|
+
##
|
141
|
+
# Set the subject and message on the new topic form
|
142
|
+
|
143
|
+
def set_subject_and_message(form, subject, message)
|
144
|
+
form.subject = subject
|
145
|
+
form.message = message
|
146
|
+
form
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Validate the result of posting the new topic
|
151
|
+
# FIXME this validation is copied into post module as well
|
152
|
+
|
153
|
+
def validate_new_topic_result(page)
|
154
|
+
error = page.search("//table[@class='errorTable']")
|
155
|
+
if error
|
156
|
+
msgs = error.search("//td")
|
157
|
+
|
158
|
+
# throttled
|
159
|
+
too_many = (msgs.last.text =~
|
160
|
+
/You have exceeded the number of posts permitted in the time span/ rescue
|
161
|
+
false)
|
162
|
+
raise ThrottledError.new(msgs.last.text.gsub(/\s+/m,' ').strip) if too_many
|
163
|
+
|
164
|
+
# general error
|
165
|
+
had_error = (error.last.text =~
|
166
|
+
/Error: Message Not Posted/ rescue
|
167
|
+
false)
|
168
|
+
raise TopicError.new(error.last.text.gsub(/\s+/m,' ').strip) if had_error
|
169
|
+
end
|
170
|
+
|
171
|
+
page
|
172
|
+
end
|
173
|
+
|
174
|
+
##
|
175
|
+
# Get the new topic identifier from the result page
|
176
|
+
|
177
|
+
def get_topic_from_result(page)
|
178
|
+
begin
|
179
|
+
tid = page.form('frmMessageForm')['TID'].to_i
|
180
|
+
raise StandardError.new("new topic id not found") if tid.zero?
|
181
|
+
tid
|
182
|
+
rescue StandardError => err
|
183
|
+
raise Impostor::TopicError.new(err)
|
184
|
+
end
|
185
|
+
end
|
186
|
+
|
187
|
+
end
|
188
|
+
|
189
|
+
end
|
190
|
+
end
|
data/lib/impostor.rb
CHANGED
@@ -1,6 +1,109 @@
|
|
1
|
-
|
2
|
-
|
3
|
-
|
4
|
-
|
1
|
+
%W{ mechanize nokogiri cgi }.each do |g|
|
2
|
+
begin
|
3
|
+
require g
|
4
|
+
rescue LoadError
|
5
|
+
require 'rubygems'
|
6
|
+
require g
|
7
|
+
end
|
8
|
+
end
|
9
|
+
require 'logger'
|
5
10
|
|
6
|
-
|
11
|
+
Dir.glob(File.join(File.dirname(__FILE__), 'impostor/**/*.rb')).each {|f| require f }
|
12
|
+
|
13
|
+
class Impostor
|
14
|
+
|
15
|
+
##
|
16
|
+
# imPOSTor posts messages to non-RESTful forums and blogs
|
17
|
+
#
|
18
|
+
# == Example
|
19
|
+
# require 'rubygems'
|
20
|
+
# require 'impostor'
|
21
|
+
#
|
22
|
+
# # config yaml has options specefic to wwf79, wwf80, phpbb2, etc.
|
23
|
+
# # read the impostor docs for options to the kind of forum in use
|
24
|
+
# # config can be keyed by symbols or strings
|
25
|
+
# post = Impostor.new(YAML.load_file('config.yml'))
|
26
|
+
# message = %q!hello world is to application
|
27
|
+
# programmers as tea pots are to graphics programmers!
|
28
|
+
# # your application store forum and topic ids
|
29
|
+
# post.post(forum=5,topic=10,message)
|
30
|
+
# # make a new topic
|
31
|
+
# subject = "about programmers..."
|
32
|
+
# post.new_topic(forum=7,subject,message)
|
33
|
+
#
|
34
|
+
# keys and values that can be set in the impostor configuration
|
35
|
+
#
|
36
|
+
# :type - kind of imPOSTor, :phpbb2, :wwf79, :wwf80, etc.
|
37
|
+
# :username - forum username
|
38
|
+
# :password - forum password
|
39
|
+
# :topics_cache - cache of forum topics
|
40
|
+
# :user_agent - Mechanize browser user-agent
|
41
|
+
# :cookie_jar - saved cookies from Mechanize browser
|
42
|
+
# :app_root - url to forum
|
43
|
+
# :login_page - forum login page
|
44
|
+
# :logger - A logger object or path ot a logger file.
|
45
|
+
# :sleep_before_post - Number of seconds delay before posting to forum
|
46
|
+
#
|
47
|
+
# See documentation for each type of imPOSTor for additional configuration
|
48
|
+
# parameters that are needed for the specific kind of imPOSTor. A sample
|
49
|
+
# configuration is provided in the documentation for each.
|
50
|
+
|
51
|
+
|
52
|
+
##
|
53
|
+
# Gem version of Impostor
|
54
|
+
|
55
|
+
VERSION = '1.0.0'
|
56
|
+
|
57
|
+
##
|
58
|
+
# Pass in a config hash to initialize
|
59
|
+
|
60
|
+
def initialize(config={})
|
61
|
+
@config = Config.new(config)
|
62
|
+
@auth = Auth.new(@config)
|
63
|
+
@post = Post.new(@config, @auth)
|
64
|
+
@topic = Topic.new(@config, @auth)
|
65
|
+
|
66
|
+
type = @config.type
|
67
|
+
raise ConfigError.new("Missing 'type' key in configuration") unless type
|
68
|
+
|
69
|
+
extend eval("Impostor::#{type.to_s.capitalize}")
|
70
|
+
end
|
71
|
+
|
72
|
+
##
|
73
|
+
# our version
|
74
|
+
|
75
|
+
def version
|
76
|
+
VERSION
|
77
|
+
end
|
78
|
+
|
79
|
+
##
|
80
|
+
# Post the message
|
81
|
+
|
82
|
+
def post(forum, topic, message)
|
83
|
+
@post.post(forum, topic, message)
|
84
|
+
end
|
85
|
+
|
86
|
+
##
|
87
|
+
# Make a new topic
|
88
|
+
|
89
|
+
def new_topic(forum, subject, message)
|
90
|
+
@topic.new_topic(forum, subject, message)
|
91
|
+
end
|
92
|
+
|
93
|
+
##
|
94
|
+
# Login
|
95
|
+
|
96
|
+
def login
|
97
|
+
@auth.login
|
98
|
+
end
|
99
|
+
|
100
|
+
def self.not_tested(who, what)
|
101
|
+
warn <<WARNMSG
|
102
|
+
!!!!! IMPLEMENTATION WARNING !!!!!
|
103
|
+
#{who}##{what} did not have real integration test data to work against in the
|
104
|
+
refactoring of Impostor from version 0.2.1 to 1.0.0. Please contact the author
|
105
|
+
to help supply live data allowing real integration tests for this method.
|
106
|
+
WARNMSG
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
data/spec/auth_spec.rb
ADDED
@@ -0,0 +1,148 @@
|
|
1
|
+
require File.join(File.dirname(__FILE__), 'spec_helper')
|
2
|
+
|
3
|
+
describe "impostor's authorization routines" do
|
4
|
+
|
5
|
+
describe "the no-op test impostor auth without implemented template methods" do
|
6
|
+
|
7
|
+
it "should logout only if not logged in" do
|
8
|
+
auth = self.auth
|
9
|
+
auth.should_receive(:authenticated?).once.and_return(false)
|
10
|
+
auth.logout.should_not be_true
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should logout" do
|
14
|
+
config = self.config
|
15
|
+
auth = self.auth(config)
|
16
|
+
config.should_receive(:save_topics).once
|
17
|
+
config.should_receive(:save_cookie_jar).once
|
18
|
+
auth.instance_variable_set("@authenticated", true)
|
19
|
+
|
20
|
+
auth.logout.should be_true
|
21
|
+
auth.authenticated?.should_not be_true
|
22
|
+
end
|
23
|
+
|
24
|
+
it "should login at the server only if not logged in" do
|
25
|
+
auth = self.auth
|
26
|
+
auth.should_receive(:authenticated?).once.and_return(true)
|
27
|
+
auth.login.should be_true
|
28
|
+
end
|
29
|
+
|
30
|
+
it "should raise login failure when login fails" do
|
31
|
+
auth = self.auth
|
32
|
+
auth.should_receive(:login).once.and_return(false)
|
33
|
+
lambda { auth.login_with_raises }.should raise_error(
|
34
|
+
Impostor::LoginError,
|
35
|
+
"Impostor error: not logged in (StandardError)"
|
36
|
+
)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should not raise login failure when login fails" do
|
40
|
+
auth = self.auth
|
41
|
+
auth.should_receive(:login).once.and_return(true)
|
42
|
+
lambda { auth.login_with_raises }.should_not raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should not login when template methods are not implemented" do
|
46
|
+
config = self.config
|
47
|
+
auth = self.auth(config)
|
48
|
+
login_uri = URI.parse("http://example.com/login")
|
49
|
+
config.agent.should_receive(:get).with(login_uri)
|
50
|
+
|
51
|
+
lambda { auth.login }.should raise_error(
|
52
|
+
Impostor::MissingTemplateMethodError,
|
53
|
+
"Impostor error: logged_in? must be implemented (StandardError)"
|
54
|
+
)
|
55
|
+
end
|
56
|
+
|
57
|
+
it "should raise not implemented error when logged_in? called" do
|
58
|
+
auth = self.auth
|
59
|
+
lambda { auth.logged_in?(nil) }.should raise_error(
|
60
|
+
Impostor::MissingTemplateMethodError,
|
61
|
+
"Impostor error: logged_in? must be implemented (StandardError)"
|
62
|
+
)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "should return a page from fetch_login_page" do
|
66
|
+
config = self.config
|
67
|
+
auth = self.auth(config)
|
68
|
+
login_uri = URI.parse("http://example.com/login")
|
69
|
+
config.agent.should_receive(:get).with(login_uri)
|
70
|
+
|
71
|
+
lambda {
|
72
|
+
auth.fetch_login_page
|
73
|
+
}.should_not raise_error
|
74
|
+
end
|
75
|
+
|
76
|
+
it "should handle an error in fetch_login_page" do
|
77
|
+
config = self.config
|
78
|
+
auth = self.auth(config)
|
79
|
+
login_uri = URI.parse("http://example.com/login")
|
80
|
+
config.agent.should_receive(:get).with(login_uri).and_raise(StandardError)
|
81
|
+
|
82
|
+
lambda {
|
83
|
+
auth.fetch_login_page
|
84
|
+
}.should raise_error( Impostor::LoginError )
|
85
|
+
end
|
86
|
+
|
87
|
+
it "should raise not implemented error when get_login_form called" do
|
88
|
+
auth = self.auth
|
89
|
+
lambda { auth.get_login_form(nil) }.should raise_error(
|
90
|
+
Impostor::MissingTemplateMethodError,
|
91
|
+
"Impostor error: get_login_form must be implemented (StandardError)"
|
92
|
+
)
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should raise not implemented error when set_username_and_password called" do
|
96
|
+
auth = self.auth
|
97
|
+
lambda { auth.set_username_and_password(nil) }.should raise_error(
|
98
|
+
Impostor::MissingTemplateMethodError,
|
99
|
+
"Impostor error: set_username_and_password must be implemented (StandardError)"
|
100
|
+
)
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should raise not implemented error when post_login called" do
|
104
|
+
auth = self.auth
|
105
|
+
form = mock "form"
|
106
|
+
page = mock "page"
|
107
|
+
form.should_receive(:submit).and_return(page)
|
108
|
+
lambda { auth.post_login(form).should == page }.should_not raise_error
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should login via composed template methods" do
|
112
|
+
|
113
|
+
auth = self.auth
|
114
|
+
|
115
|
+
login_page = mock "page"
|
116
|
+
logged_in_page = mock "page"
|
117
|
+
form = mock "form"
|
118
|
+
|
119
|
+
auth.should_receive(:authenticated?).once.and_return(false)
|
120
|
+
auth.should_receive(:fetch_login_page).once.and_return(login_page)
|
121
|
+
auth.should_receive(:logged_in?).with(login_page).once.and_return(false)
|
122
|
+
auth.should_receive(:get_login_form).with(login_page).once.and_return(form)
|
123
|
+
auth.should_receive(:set_username_and_password).with(form).once
|
124
|
+
|
125
|
+
auth.should_receive(:post_login).with(form).once.and_return(logged_in_page)
|
126
|
+
auth.should_receive(:logged_in?).with(logged_in_page).once.and_return(true)
|
127
|
+
|
128
|
+
lambda {
|
129
|
+
auth.login.should be_true
|
130
|
+
}.should_not raise_error
|
131
|
+
|
132
|
+
end
|
133
|
+
|
134
|
+
it "should not login via composed template methods if already logged in" do
|
135
|
+
auth = self.auth
|
136
|
+
auth.should_receive(:authenticated?).once.and_return(true)
|
137
|
+
|
138
|
+
auth.should_not_receive(:fetch_login_page)
|
139
|
+
auth.should_not_receive(:logged_in?)
|
140
|
+
auth.should_not_receive(:login_form)
|
141
|
+
|
142
|
+
lambda {
|
143
|
+
auth.login.should be_true
|
144
|
+
}.should_not raise_error
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
end
|
@@ -1,8 +1,3 @@
|
|
1
|
-
$:.unshift File.join(File.dirname(__FILE__), "..", "lib")
|
2
|
-
|
3
|
-
require 'net/http'
|
4
|
-
require 'net/https'
|
5
|
-
|
6
1
|
# monkey patch Net::HTTP so un caged requests don't go over the wire
|
7
2
|
module Net #:nodoc:
|
8
3
|
class HTTP #:nodoc:
|
@@ -17,22 +12,18 @@ module Net #:nodoc:
|
|
17
12
|
:port => self.port, :path => query[0]}
|
18
13
|
opts[:query] = query[1] if query[1]
|
19
14
|
uri = uri_cls.build(opts)
|
20
|
-
|
15
|
+
if uri.to_s =~ /^http:\/\/localhost\//
|
16
|
+
old_net_http_request(req, body, &block)
|
17
|
+
else
|
18
|
+
raise ArgumentError.new("#{req.method} method to #{uri} not being handled in testing")
|
19
|
+
end
|
21
20
|
end
|
22
21
|
|
23
22
|
def connect
|
23
|
+
if address.to_s == "localhost"
|
24
|
+
old_net_http_connect
|
25
|
+
end
|
24
26
|
end
|
25
27
|
|
26
28
|
end
|
27
29
|
end
|
28
|
-
|
29
|
-
module TestHelper
|
30
|
-
|
31
|
-
##
|
32
|
-
# helps load pages
|
33
|
-
|
34
|
-
def load_page(file)
|
35
|
-
IO.readlines("#{File.dirname(__FILE__)}/fixtures/#{file}")
|
36
|
-
end
|
37
|
-
|
38
|
-
end
|