impostor 0.2.1 → 1.0.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/.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
|