Tobias Gritschacher has submitted this change and it was merged.

Change subject: Module for interacting with Wikibase-API in browser tests
......................................................................


Module for interacting with Wikibase-API in browser tests

Change-Id: Ibb10814ce9e8a4306e162e113423baf25459e657
---
M selenium_cuc/features/statement.feature
M selenium_cuc/features/step_definitions/entity_steps.rb
M selenium_cuc/features/support/env.rb
A selenium_cuc/features/support/modules/wikibase_api_module.rb
M selenium_cuc/features/support/pages/item_page.rb
M selenium_cuc/features/support/utils/utils.rb
6 files changed, 208 insertions(+), 101 deletions(-)

Approvals:
  Tobias Gritschacher: Verified; Looks good to me, approved



diff --git a/selenium_cuc/features/statement.feature 
b/selenium_cuc/features/statement.feature
index e9210a6..9dbf908 100644
--- a/selenium_cuc/features/statement.feature
+++ b/selenium_cuc/features/statement.feature
@@ -46,7 +46,7 @@
     | click the statement cancel button |
     | press the ESC key in the entity selector input field |
 
-  @ui_only
+  @ui_only @repo_login
   Scenario: Select a property
     Given There are properties with the following handles and datatypes:
       | stringprop | string |
@@ -58,7 +58,7 @@
       And Entity selector input element should be there
       And Statement value input element should be there
 
-  @ui_only
+  @ui_only @repo_login
   Scenario: Select a property and enter a statement value
     Given There are properties with the following handles and datatypes:
       | stringprop | string |
@@ -71,7 +71,7 @@
       And Entity selector input element should be there
       And Statement value input element should be there
 
-  @ui_only
+  @ui_only @repo_login
   Scenario Outline: Cancel statement after selecting a property
     Given There are properties with the following handles and datatypes:
       | stringprop | string |
@@ -91,7 +91,7 @@
     | press the ESC key in the entity selector input field |
     | press the ESC key in the statement value input field |
 
-  @ui_only
+  @ui_only @repo_login
   Scenario: Select a property, enter a statement value and clear the property
     Given There are properties with the following handles and datatypes:
       | stringprop | string |
diff --git a/selenium_cuc/features/step_definitions/entity_steps.rb 
b/selenium_cuc/features/step_definitions/entity_steps.rb
index 48d1e91..0827acd 100644
--- a/selenium_cuc/features/step_definitions/entity_steps.rb
+++ b/selenium_cuc/features/step_definitions/entity_steps.rb
@@ -8,17 +8,20 @@
 
 Given /^I am on an item page$/ do
   item_data = '{"labels":{"en":{"language":"en","value":"' + 
generate_random_string(8) + 
'"}},"descriptions":{"en":{"language":"en","value":"' + 
generate_random_string(20) + '"}}}'
-  item = create_new_entity(item_data, "item")
-  @item_under_test = item
-  on(ItemPage).navigate_to_entity item["url"]
+  wb_api = WikibaseAPI::Gateway.new(URL.repo_api)
+  @item_under_test = wb_api.wb_create_entity(item_data, "item")
+  on(ItemPage).navigate_to_entity @item_under_test["url"]
 end
 
 Given /^There are properties with the following handles and datatypes:$/ do 
|props|
-  @properties = create_new_properties(props.raw)
+  wb_api = WikibaseAPI::Gateway.new(URL.repo_api)
+  wb_api.login(ENV["WB_REPO_USERNAME"], ENV["WB_REPO_PASSWORD"])
+  @properties = wb_api.wb_create_properties(props.raw)
 end
 
 Given /^There are items with the following handles:$/ do |handles|
-  @items = create_new_items(handles.raw)
+  wb_api = WikibaseAPI::Gateway.new(URL.repo_api)
+  @items = wb_api.wb_create_items(handles.raw)
 end
 
 Given /^The copyright warning has been dismissed$/ do
@@ -31,14 +34,15 @@
 
 Given /^I am on an item page with empty label and description$/ do
   item_data = '{"labels":{"en":{"language":"en","value":"' + '' + 
'"}},"descriptions":{"en":{"language":"en","value":"' + '' + '"}}}'
-  item = create_new_entity(item_data, "item")
-  @item_under_test = item
-  on(ItemPage).navigate_to_entity item["url"]
+  wb_api = WikibaseAPI::Gateway.new(URL.repo_api)
+  @item_under_test = wb_api.wb_create_entity(item_data, "item")
+  on(ItemPage).navigate_to_entity @item_under_test["url"]
 end
 
 Given /^The following sitelinks do not exist:$/ do |sitelinks|
+  wb_api = WikibaseAPI::Gateway.new(URL.repo_api)
   sitelinks.raw.each do |sitelink|
-    remove_sitelink(sitelink[0], sitelink[1]).should be_true
+    wb_api.wb_remove_sitelink(sitelink[0], sitelink[1]).should be_true
   end
 end
 
diff --git a/selenium_cuc/features/support/env.rb 
b/selenium_cuc/features/support/env.rb
index 14d2bb6..cc9ee8b 100644
--- a/selenium_cuc/features/support/env.rb
+++ b/selenium_cuc/features/support/env.rb
@@ -46,3 +46,8 @@
 
   browser
 end
+
+Before("@repo_login") do
+  abort("WB_REPO_USERNAME environment variable is not defined! Please export a 
value for that variable before proceeding.") unless ENV["WB_REPO_USERNAME"]
+  abort("WB_REPO_PASSWORD environment variable is not defined! Please export a 
value for that variable before proceeding.") unless ENV["WB_REPO_PASSWORD"]
+end
diff --git a/selenium_cuc/features/support/modules/wikibase_api_module.rb 
b/selenium_cuc/features/support/modules/wikibase_api_module.rb
new file mode 100644
index 0000000..84a5357
--- /dev/null
+++ b/selenium_cuc/features/support/modules/wikibase_api_module.rb
@@ -0,0 +1,186 @@
+# Author:: Tobias Gritschacher (tobias.gritschac...@wikimedia.de)
+# License:: GNU GPL v2+
+#
+# Parts reused and modified from http://rubygems.org/gems/mediawiki-gateway
+#
+# module for interacting with WikibaseAPI
+
+require "rest_client"
+require "uri"
+require "active_support"
+
+module WikibaseAPI
+
+  class Gateway
+    # Set up a WikibaseAPI::Gateway
+    #
+    # [url] Path to API of target Wikibase Installation
+    def initialize(url)
+      @wiki_url = url
+      @headers = { "User-Agent" => "WikibaseAPI::Gateway", "Accept-Encoding" 
=> "gzip" }
+      @cookies = {}
+    end
+
+    # Login
+    #
+    # [username] Username
+    # [password] Password
+    #
+    # Throws WikibaseAPI::Unauthorized if login fails
+    def login(username, password, domain = "local")
+      form_data = {"action" => "login", "lgname" => username, "lgpassword" => 
password, "lgdomain" => domain}
+      make_api_request(form_data)
+    end
+
+    # creates a new entity via the API
+    def wb_create_entity(data, type = "item")
+      form_data = {"action" => "wbeditentity", "new" => type, "data" => data,
+                   "summary" => "entity created by selenium test", "token" => 
get_token("edit")}
+      resp = make_api_request(form_data)
+      check_wb_api_success(resp)
+
+      id = resp["entity"]["id"]
+      url = URL.repo_url(ITEM_NAMESPACE + id + "?setlang=" + LANGUAGE_CODE)
+      entity_data = ActiveSupport::JSON.decode(data)
+
+      {"id" => id, "url" => url, "label" => 
entity_data["labels"]["en"]["value"],
+       "description" => entity_data["descriptions"]["en"]["value"]}
+    end
+
+    # creates new properties by calling wb_create_entity multiple times
+    def wb_create_properties(props)
+      properties = Hash.new
+
+      props.each do |prop|
+        handle = prop[0]
+        type = prop[1]
+        data = '{"labels":{"en":{"language":"en","value":"' + 
generate_random_string(8) +
+            '"}},"descriptions":{"en":{"language":"en","value":"' + 
generate_random_string(20) +
+            '"}},"datatype":"' + type + '"}'
+        property = wb_create_entity(data, "property")
+        properties[handle] = property
+      end
+
+      properties
+    end
+
+    # creates items by calling wb_create_entity multiple times
+    def wb_create_items(handles)
+      items = Hash.new
+
+      handles.each do |handle|
+        data = '{"labels":{"en":{"language":"en","value":"' + 
generate_random_string(8) +
+            '"}},"descriptions":{"en":{"language":"en","value":"' + 
generate_random_string(20) + '"}}}'
+        item = wb_create_entity(data, "item")
+        items[handle] = item
+      end
+
+      items
+    end
+
+    # removes a sitelink
+    def wb_set_sitelink(entity_identifier, linksite, linktitle)
+      form_data = entity_identifier.merge({"action" => "wbsetsitelink", 
"linksite" => linksite, "linktitle" => linktitle,
+                   "summary" => "Sitelink set by Selenium test API", "token" 
=> get_token("edit")})
+
+      make_api_request(form_data)
+    end
+
+    def wb_remove_sitelink(siteid, pagename)
+      entity_identifier = {"site" => siteid, "title" => pagename}
+      resp = wb_set_sitelink(entity_identifier, siteid, "")
+
+      if resp["success"] != 1 && resp["error"]["code"] != "no-such-entity-link"
+        msg = "Failed to remove sitelink " + siteid + ": API error"
+        raise APIError.new("error", msg)
+      end
+
+      return true
+    end
+
+    private
+
+    # Fetch token (type "delete", "edit", "email", "import", "move", "protect")
+    def get_token(type)
+      form_data = {"action" => "tokens", "type" => type}
+      res = make_api_request(form_data)
+      token = res["tokens"][type + "token"]
+      raise Unauthorized.new "User is not permitted to perform this operation: 
#{type}" if token.nil?
+      token
+    end
+
+    # Make generic request to API
+    #
+    # [form_data] hash or string of attributes to post
+    #
+    # Returns JSON document
+    def make_api_request(form_data)
+      form_data.merge!("format" => "json")
+      http_send(@wiki_url, form_data, @headers.merge({:cookies => @cookies})) 
do |response, &block|
+        # Check response for errors and return JSON
+        raise MediaWiki::Exception.new "Bad response: #{response}" unless 
response.code >= 200 and response.code < 300
+        json_resp = get_response(response.dup)
+        if form_data["action"] == "login"
+          login_result = json_resp["login"]["result"]
+          @cookies.merge!(response.cookies)
+          case login_result
+            when "Success" then # do nothing
+            when "NeedToken" then make_api_request(form_data.merge("lgtoken" 
=> json_resp["login"]["token"]))
+            else raise Unauthorized.new "Login failed: " + login_result
+          end
+        end
+        return json_resp
+      end
+    end
+
+    # Execute the HTTP request using either GET or POST as appropriate
+    def http_send(url, form_data, headers, &block)
+      if form_data["action"] == "query"
+        headers[:params] = form_data
+        RestClient.get url, headers, &block
+      else
+        RestClient.post url, form_data, headers, &block
+      end
+    end
+
+    # Get JSON response
+    def get_response(response)
+      ActiveSupport::JSON.decode(response)
+    end
+
+    def warning(msg)
+        raise APIError.new("warning", msg)
+    end
+
+    def check_wb_api_success(response)
+      if response["success"] != 1
+        msg = "API error: " + response["error"]["info"]
+        raise APIError.new("error", msg)
+      end
+    end
+
+  end
+
+  # General exception occurred within WikibaseAPI::Gateway, and parent class 
for WikibaseAPI::APIError, WikibaseAPI::Unauthorized.
+  class WBException < Exception
+  end
+
+  # Wrapper for errors returned by MediaWiki API.  Possible codes are defined 
in http://www.mediawiki.org/wiki/API:Errors_and_warnings.
+  # Warnings also throw errors with code "warning"
+  class APIError < WikibaseAPI::WBException
+
+    def initialize(code, info)
+      @code = code
+      @info = info
+      @message = "API error: code '#{code}', info '#{info}'"
+    end
+
+    def to_s
+      "#{self.class.to_s}: #{@message}"
+    end
+  end
+
+  # User is not authorized to perform this operation.  Also thrown if login 
fails.
+  class Unauthorized < WikibaseAPI::WBException
+  end
+end
diff --git a/selenium_cuc/features/support/pages/item_page.rb 
b/selenium_cuc/features/support/pages/item_page.rb
index f5a4b66..01f1da6 100644
--- a/selenium_cuc/features/support/pages/item_page.rb
+++ b/selenium_cuc/features/support/pages/item_page.rb
@@ -6,8 +6,6 @@
 #
 # page object for item page
 
-#require "ruby_selenium"
-
 class ItemPage
   include PageObject
   include EntityPage
diff --git a/selenium_cuc/features/support/utils/utils.rb 
b/selenium_cuc/features/support/utils/utils.rb
index 433d295..0462a50 100644
--- a/selenium_cuc/features/support/utils/utils.rb
+++ b/selenium_cuc/features/support/utils/utils.rb
@@ -15,89 +15,3 @@
   length.times { string << chars[rand(chars.size)] }
   return string
 end
-
-def create_new_properties(props)
-  properties = Hash.new
-
-  props.each do |prop|
-    handle = prop[0]
-    type = prop[1]
-    data = '{"labels":{"en":{"language":"en","value":"' + 
generate_random_string(8) +
-           '"}},"descriptions":{"en":{"language":"en","value":"' + 
generate_random_string(20) +
-           '"}},"datatype":"' + type + '"}'
-    property = create_new_entity(data, "property")
-    properties[handle] = property
-  end
-
-  properties
-end
-
-def create_new_items(handles)
-  items = Hash.new
-
-  handles.each do |handle|
-    data = '{"labels":{"en":{"language":"en","value":"' + 
generate_random_string(8) +
-           '"}},"descriptions":{"en":{"language":"en","value":"' + 
generate_random_string(20) + '"}}}'
-    item = create_new_entity(data, "item")
-    items[handle] = item
-  end
-
-  items
-end
-
-# creates a new entity via the API
-def create_new_entity(data, type = "item")
-  uri = URI(URL.repo_api)
-
-  request = Net::HTTP::Post.new(uri.to_s)
-  request.set_form_data(
-    "action" => "wbeditentity",
-    "token" => "+\\",
-    "new" => type,
-    "data" => data,
-    "format" => "json",
-    "summary" => "entity created by selenium test"
-  )
-
-  response = Net::HTTP.start(uri.hostname, uri.port) do |http|
-    http.request(request)
-  end
-  resp = ActiveSupport::JSON.decode(response.body)
-
-  if resp["success"] != 1
-    abort("Failed to create new entity: API error: " + resp["error"]["info"])
-  end
-
-  id = resp["entity"]["id"]
-  url = URL.repo_url(ITEM_NAMESPACE + id + "?setlang=" + LANGUAGE_CODE)
-  entity_data = ActiveSupport::JSON.decode(data)
-  entity = {"id" => id, "url" => url, "label" => 
entity_data["labels"]["en"]["value"], "description" => 
entity_data["descriptions"]["en"]["value"]}
-  return entity
-end
-
-# removes a sitelink
-def remove_sitelink(siteid, pagename)
-  uri = URI(URL.repo_api)
-
-  request = Net::HTTP::Post.new(uri.to_s)
-  request.set_form_data(
-      "action" => "wbsetsitelink",
-      "token" => "+\\",
-      "site" => siteid,
-      "title" => pagename,
-      "linksite" => siteid,
-      "format" => "json",
-      "summary" => "sitelink removed by selenium test"
-  )
-
-  response = Net::HTTP.start(uri.hostname, uri.port) do |http|
-    http.request(request)
-  end
-  resp = ActiveSupport::JSON.decode(response.body)
-
-  if resp["success"] != 1 && resp["error"]["code"] != "no-such-entity-link"
-    abort("Failed to remove sitelink " + siteid + ": API error")
-  end
-
-  return true
-end

-- 
To view, visit https://gerrit.wikimedia.org/r/98163
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: merged
Gerrit-Change-Id: Ibb10814ce9e8a4306e162e113423baf25459e657
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/Wikibase
Gerrit-Branch: master
Gerrit-Owner: Tobias Gritschacher <tobias.gritschac...@wikimedia.de>
Gerrit-Reviewer: Cmcmahon <cmcma...@wikimedia.org>
Gerrit-Reviewer: Jhall <jh...@wikimedia.org>
Gerrit-Reviewer: Tobias Gritschacher <tobias.gritschac...@wikimedia.de>
Gerrit-Reviewer: Zfilipin <zfili...@wikimedia.org>
Gerrit-Reviewer: jenkins-bot

_______________________________________________
MediaWiki-commits mailing list
MediaWiki-commits@lists.wikimedia.org
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to