Merge branch 'develop'

This commit is contained in:
Teemu Patja 2017-12-15 12:16:14 +02:00
commit c7e4224e3b
No known key found for this signature in database
GPG Key ID: F5B7035E6580FD4C
16 changed files with 658 additions and 12 deletions

4
.gitignore vendored
View File

@ -17,6 +17,10 @@ profiles.clj
*.iml
*.ipr
*.log
*.pyc
*result.xml
.cache
.idea
resources/contracts
node_modules
.DS_Store

View File

@ -1,27 +1,72 @@
(ns commiteth.util.crypto-fiat-value
(:require [clj-http.client :as http]
[clojure.string :as str]
[mount.core :as mount]
[clojure.tools.logging :as log]
[commiteth.config :refer [env]]
[clojure.data.json :as json]))
(defn get-token-usd-price
(defn fiat-api-provider []
(env :fiat-api-provider :coinmarketcap))
(defn json-api-request [url]
(->> (http/get url)
(:body)
(json/read-str)))
(defn get-token-usd-price-cryptonator
"Get current USD value for a token using cryptonator API"
[token]
(let [url (str "https://api.cryptonator.com/api/ticker/"
[tla]
(let [token (subs (str tla) 1)
url (str "https://api.cryptonator.com/api/ticker/"
token
"-usd")
m (->> (http/get url)
(:body)
(json/read-str))]
m (json-api-request url)]
(-> (get-in m ["ticker" "price"])
(read-string))))
(def tla-to-id-mapping (atom {}))
(defn make-tla-to-id-mapping
"Coinmarketcap API uses it's own IDs for tokens instead of TLAs"
[]
(let [data (json-api-request "https://api.coinmarketcap.com/v1/ticker/?limit=0")]
(into {} (map
(fn [x] [(keyword (get x "symbol")) (get x "id")])
data))))
(defn get-token-usd-price-coinmarketcap
"Get current USD value for a token using coinmarketcap API"
[tla]
(let [token-id (get @tla-to-id-mapping tla)
url (format "https://api.coinmarketcap.com/v1/ticker/%s" token-id)
data (json-api-request url)]
(-> (first data)
(get "price_usd")
(read-string))))
(defn- get-price-fn []
(let [fns {:cryptonator get-token-usd-price-cryptonator
:coinmarketcap get-token-usd-price-coinmarketcap}]
(get fns (fiat-api-provider))))
(defn bounty-usd-value
"Get current USD value of a bounty. bounty is a map of token-tla (keyword) to value"
[bounty]
(reduce + (map (fn [[token value]]
(let [tla (subs (str token) 1)
usd-price (get-token-usd-price tla)]
(* usd-price value)))
bounty)))
(let [get-token-usd-price (get-price-fn)]
(reduce + (map (fn [[tla value]]
(let [usd-price (get-token-usd-price tla)]
(* usd-price value)))
bounty))))
(mount/defstate
crypto-fiat-util
:start
(do
(reset! tla-to-id-mapping (make-tla-to-id-mapping))
(log/info "crypto-fiat-util started"))
:stop
(log/info "crypto-fiat-util stopped"))

View File

@ -0,0 +1,105 @@
import logging
from selenium.webdriver.common.by import By
from selenium.common.exceptions import TimeoutException
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver.support import expected_conditions
class BaseElement(object):
class Locator(object):
def __init__(self, by, value):
self.by = by
self.value = value
@classmethod
def xpath_selector(locator, value):
return locator(By.XPATH, value)
@classmethod
def css_selector(locator, value):
return locator(By.CSS_SELECTOR, value)
@classmethod
def id(locator, value):
return locator(By.ID, value)
@classmethod
def name(locator, value):
return locator(By.NAME, value)
def __str__(self, *args):
return "%s:%s" % (self.by, self.value)
def __init__(self, driver):
self.driver = driver
self.locator = None
@property
def name(self):
return self.__class__.__name__
def navigate(self):
return None
def find_element(self):
logging.info('Looking for %s' % self.name)
return self.wait_for_element()
def find_elements(self):
logging.info('Looking for %s' % self.name)
return self.driver.find_elements(self.locator.by,
self.locator.value)
def wait_for_element(self, seconds=5):
return WebDriverWait(self.driver, seconds).until(
expected_conditions.presence_of_element_located((self.locator.by, self.locator.value)))
def wait_for_clickable(self, seconds=5):
return WebDriverWait(self.driver, seconds).until(
expected_conditions.element_to_be_clickable((self.locator.by, self.locator.value)))
def is_element_present(self, sec=5):
try:
self.wait_for_element(sec)
return True
except TimeoutException:
return False
class BaseEditBox(BaseElement):
def __init__(self, driver):
super(BaseEditBox, self).__init__(driver)
def send_keys(self, value):
self.find_element().send_keys(value)
logging.info('Type %s to %s' % (value, self.name))
def clear(self):
self.find_element().clear()
logging.info('Clear text in %s' % self.name)
class BaseText(BaseElement):
def __init__(self, driver):
super(BaseText, self).__init__(driver)
@property
def text(self):
text = self.find_element().text
logging.info('%s is %s' % (self.name, text))
return text
class BaseButton(BaseElement):
def __init__(self, driver):
super(BaseButton, self).__init__(driver)
def click(self):
self.wait_for_clickable().click()
logging.info('Tap on %s' % self.name)
return self.navigate()

View File

@ -0,0 +1,17 @@
from datetime import datetime
class BasePageObject(object):
def __init__(self, driver):
self.driver = driver
def get_url(self, url):
self.driver.get(url)
def refresh(self):
self.driver.refresh()
@property
def time_now(self):
return datetime.now().strftime('%-m%-d%-H%-M%-S')

View File

@ -0,0 +1,25 @@
from pages.base_page import BasePageObject
from pages.base_element import *
class BountiesHeader(BaseText):
def __init__(self, driver):
super(BountiesHeader, self).__init__(driver)
self.locator = self.Locator.css_selector('.open-bounties-header')
class TopHuntersHeader(BaseText):
def __init__(self, driver):
super(TopHuntersHeader, self).__init__(driver)
self.locator = self.Locator.css_selector('.top-hunters-header')
class BountiesPage(BasePageObject):
def __init__(self, driver):
super(BountiesPage, self).__init__(driver)
self.driver = driver
self.bounties_header = BountiesHeader(self.driver)
self.top_hunters_header = TopHuntersHeader(self.driver)

View File

@ -0,0 +1,23 @@
from pages.base_page import BasePageObject
from pages.base_element import *
class LoginButton(BaseButton):
def __init__(self, driver):
super(LoginButton, self).__init__(driver)
self.locator = self.Locator.id('button-login')
def navigate(self):
from pages.thirdparty.github import GithubPage
return GithubPage(self.driver)
class LandingPage(BasePageObject):
def __init__(self, driver):
super(LandingPage, self).__init__(driver)
self.driver = driver
self.login_button = LoginButton(self.driver)
def get_landing_page(self):
self.driver.get('https://openbounty.status.im:444/')

View File

@ -0,0 +1,173 @@
import time, pytest
from pages.base_element import *
from pages.base_page import BasePageObject
class EmailEditbox(BaseEditBox):
def __init__(self, driver):
super(EmailEditbox, self).__init__(driver)
self.locator = self.Locator.id('login_field')
class PasswordEditbox(BaseEditBox):
def __init__(self, driver):
super(PasswordEditbox, self).__init__(driver)
self.locator = self.Locator.id('password')
class SignInButton(BaseButton):
def __init__(self, driver):
super(SignInButton, self).__init__(driver)
self.locator = self.Locator.name('commit')
class AuthorizeStatusOpenBounty(BaseButton):
def __init__(self, driver):
super(AuthorizeStatusOpenBounty, self).__init__(driver)
self.locator = self.Locator.css_selector('[data-octo-click="oauth_application_authorization"]')
def navigate(self):
from pages.openbounty.bounties import BountiesPage
return BountiesPage(self.driver)
class PermissionTypeText(BaseText):
def __init__(self, driver):
super(PermissionTypeText, self).__init__(driver)
self.locator = self.Locator.css_selector('.permission-title')
class InstallButton(BaseButton):
def __init__(self, driver):
super(InstallButton, self).__init__(driver)
self.locator = self.Locator.css_selector('.btn-primary')
class OrganizationButton(BaseButton):
def __init__(self, driver):
super(OrganizationButton, self).__init__(driver)
self.locator = self.Locator.css_selector('[alt="@Org4"]')
class AllRepositoriesButton(BaseButton):
def __init__(self, driver):
super(AllRepositoriesButton, self).__init__(driver)
self.locator = self.Locator.id('install_target_all')
class IntegrationPermissionsGroup(BaseText):
def __init__(self, driver):
super(IntegrationPermissionsGroup, self).__init__(driver)
self.locator = self.Locator.css_selector('.integrations-permissions-group')
class NewIssueButton(BaseButton):
def __init__(self, driver):
super(NewIssueButton, self).__init__(driver)
self.locator = self.Locator.css_selector(".subnav [role='button']")
class IssueTitleEditBox(BaseEditBox):
def __init__(self, driver):
super(IssueTitleEditBox, self).__init__(driver)
self.locator = self.Locator.id("issue_title")
class LabelsButton(BaseButton):
def __init__(self, driver):
super(LabelsButton, self).__init__(driver)
self.locator = self.Locator.css_selector("button[aria-label='Apply labels to this issue']")
class BountyLabel(BaseButton):
def __init__(self, driver):
super(LabelsButton.BountyLabel, self).__init__(driver)
self.locator = self.Locator.css_selector("[data-name='bounty']")
class CrossButton(BaseButton):
def __init__(self, driver):
super(LabelsButton.CrossButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector(
"//span[text()='Apply labels to this issue']/../*[@aria-label='Close']")
class SubmitNewIssueButton(BaseButton):
def __init__(self, driver):
super(SubmitNewIssueButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//button[contains(text(), "
"'Submit new issue')]")
class ContractBody(BaseText):
def __init__(self, driver):
super(ContractBody, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//tbody//p[contains(text(), "
"'Current balance: 0.000000 ETH')]")
class GithubPage(BasePageObject):
def __init__(self, driver):
super(GithubPage, self).__init__(driver)
self.driver = driver
self.email_input = EmailEditbox(self.driver)
self.password_input = PasswordEditbox(self.driver)
self.sign_in_button = SignInButton(self.driver)
self.authorize_sob = AuthorizeStatusOpenBounty(self.driver)
self.permission_type = PermissionTypeText(self.driver)
self.install_button = InstallButton(self.driver)
self.organization_button = OrganizationButton(self.driver)
self.all_repositories_button = AllRepositoriesButton(self.driver)
self.integration_permissions_group = IntegrationPermissionsGroup(self.driver)
self.new_issue_button = NewIssueButton(self.driver)
self.issue_title_input = IssueTitleEditBox(self.driver)
self.labels_button = LabelsButton(self.driver)
self.bounty_label = LabelsButton.BountyLabel(self.driver)
self.cross_button = LabelsButton.CrossButton(self.driver)
self.submit_new_issue_button = SubmitNewIssueButton(self.driver)
self.contract_body = ContractBody(self.driver)
def get_issues_page(self):
self.driver.get('https://github.com/Org4/nov13/issues')
def get_sob_plugin_page(self):
self.driver.get('http://github.com/apps/status-open-bounty-app-test')
def sign_in(self, email, password):
self.email_input.send_keys(email)
self.password_input.send_keys(password)
self.sign_in_button.click()
def install_sob_plugin(self):
initial_url = self.driver.current_url
self.get_sob_plugin_page()
self.install_button.click()
self.organization_button.click()
self.all_repositories_button.click()
self.install_button.click()
self.driver.get(initial_url)
def create_new_bounty(self):
self.get_issues_page()
self.new_issue_button.click()
self.issue_title_input.send_keys('auto_test_bounty_%s' % self.time_now)
self.labels_button.click()
self.bounty_label.click()
self.cross_button.click()
self.submit_new_issue_button.click()
def get_deployed_contract(self, wait=120):
for i in range(wait):
self.refresh()
try:
return self.contract_body.text
except TimeoutException:
time.sleep(10)
pass
pytest.fail('Contract is not deployed in %s minutes!' % str(wait/60))

View File

@ -0,0 +1,88 @@
import time
from pages.base_page import BasePageObject
from pages.base_element import *
from selenium.webdriver import ActionChains
class BasePluginButton(BaseButton):
def click(self):
time.sleep(2)
self.find_element().click()
class AcceptButton(BasePluginButton):
def __init__(self, driver):
super(AcceptButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//button[.='Accept']")
class PrivacyText(BaseText):
def __init__(self, driver):
super(PrivacyText, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//a[.='Privacy']")
class ExportDenButton(BaseButton):
def __init__(self, driver):
super(ExportDenButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//p[.='Import Existing DEN']")
class SecretPhraseEditBox(BaseEditBox):
def __init__(self, driver):
super(SecretPhraseEditBox, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//textarea")
class PasswordEditBox(BaseEditBox):
def __init__(self, driver):
super(PasswordEditBox, self).__init__(driver)
self.locator = self.Locator.id('password-box')
class PasswordConfirmEditBox(BaseEditBox):
def __init__(self, driver):
super(PasswordConfirmEditBox, self).__init__(driver)
self.locator = self.Locator.id('password-box-confirm')
class OkButton(BasePluginButton):
def __init__(self, driver):
super(OkButton, self).__init__(driver)
self.locator = self.Locator.xpath_selector("//button[.='OK']")
class MetaMaskPlugin(BasePageObject):
def __init__(self, driver):
super(MetaMaskPlugin, self).__init__(driver)
self.driver = driver
self.accept_button = AcceptButton(self.driver)
self.privacy_text = PrivacyText(self.driver)
self.enter_secret_phrase = SecretPhraseEditBox(self.driver)
self.export_den_button = ExportDenButton(self.driver)
self.password_edit_box = PasswordEditBox(self.driver)
self.password_box_confirm = PasswordConfirmEditBox(self.driver)
self.ok_button = OkButton(self.driver)
def recover_access(self, passphrase, password, confirm_password):
self.get_url('chrome-extension://nkbihfbeogaeaoehlefnkodbefgpgknn/popup.html')
self.accept_button.click()
ActionChains(self.driver).move_to_element(self.privacy_text.find_element()).perform()
self.accept_button.click()
self.export_den_button.click()
self.enter_secret_phrase.send_keys(passphrase)
self.password_edit_box.send_keys(password)
self.password_box_confirm.send_keys(confirm_password)
self.ok_button.click()

View File

@ -0,0 +1,3 @@
[pytest]
norecursedirs = .git pages
addopts = -s -v --junitxml=result.xml --tb=short

View File

@ -0,0 +1,18 @@
allpairspy==2.3.0
apipkg==1.4
certifi==2017.7.27.1
chardet==3.0.4
execnet==1.4.1
idna==2.5
lxml==3.8.0
multidict==3.1.3
namedlist==1.7
py==1.4.34
pytest==3.2.1
pytest-forked==0.2
pytest-xdist==1.20.0
requests==2.18.3
selenium==2.53.6
six==1.10.0
urllib3==1.22
yarl==0.12.0

Binary file not shown.

View File

@ -0,0 +1,8 @@
class TestData(object):
def __init__(self):
self.test_name = None
test_data = TestData()

View File

@ -0,0 +1,70 @@
import pytest, sys
from selenium import webdriver
from selenium.common.exceptions import WebDriverException
from tests.postconditions import remove_application, remove_installation
from os import environ, path
from tests import test_data
class BaseTestCase:
@property
def sauce_username(self):
return environ.get('SAUCE_USERNAME')
@property
def sauce_access_key(self):
return environ.get('SAUCE_ACCESS_KEY')
@property
def executor_sauce_lab(self):
return 'http://%s:%s@ondemand.saucelabs.com:80/wd/hub' % (self.sauce_username, self.sauce_access_key)
def print_sauce_lab_info(self, driver):
sys.stdout = sys.stderr
print("SauceOnDemandSessionID=%s job-name=%s" % (driver.session_id,
pytest.config.getoption('build')))
@property
def capabilities_sauce_lab(self):
desired_caps = dict()
desired_caps['name'] = test_data.test_name
desired_caps['build'] = pytest.config.getoption('build')
desired_caps['platform'] = "MAC"
desired_caps['browserName'] = 'Chrome'
desired_caps['screenResolution'] = '2048x1536'
desired_caps['captureHtml'] = False
return desired_caps
def setup_method(self):
self.errors = []
# options = webdriver.ChromeOptions()
# options.add_argument('--start-fullscreen')
# options.add_extension(path.abspath('/resources/metamask3_12_0.crx'))
self.driver = webdriver.Remote(self.executor_sauce_lab,
desired_capabilities=self.capabilities_sauce_lab)
self.driver.implicitly_wait(5)
def verify_no_errors(self):
if self.errors:
msg = ''
for error in self.errors:
msg += (error + '\n')
pytest.fail(msg, pytrace=False)
def teardown_method(self):
remove_application(self.driver)
remove_installation(self.driver)
try:
self.print_sauce_lab_info(self.driver)
self.driver.quit()
except WebDriverException:
pass

View File

@ -0,0 +1,23 @@
from tests import test_data
from datetime import datetime
def pytest_addoption(parser):
parser.addoption("--build",
action="store",
default='SOB-' + datetime.now().strftime('%d-%b-%Y-%H-%M'),
help="Specify build name")
parser.addoption('--log',
action='store',
default=True,
help='Display each test step in terminal as plain text: True/False')
def pytest_configure(config):
if config.getoption('log'):
import logging
logging.basicConfig(level=logging.INFO)
def pytest_runtest_setup(item):
test_data.test_name = item.name

View File

@ -0,0 +1,22 @@
from selenium.webdriver.common.by import By
from selenium.common.exceptions import NoSuchElementException
def remove_application(driver):
try:
driver.get('https://github.com/settings/applications')
driver.find_element(By.CSS_SELECTOR, '.BtnGroup-item').click()
driver.find_element(By.CSS_SELECTOR, '.facebox-popup .btn-danger').click()
except NoSuchElementException:
pass
def remove_installation(driver):
try:
driver.get('https://github.com/organizations/Org4/settings/installations')
driver.find_element(By.CSS_SELECTOR, '.iconbutton').click()
driver.find_element(By.XPATH, "//a[@class='btn btn-danger']").click()
driver.find_element(By.CSS_SELECTOR, '.facebox-popup .btn-danger').click()
except NoSuchElementException:
pass

View File

@ -0,0 +1,22 @@
import pytest
from os import environ
from pages.openbounty.landing import LandingPage
from tests.basetestcase import BaseTestCase
@pytest.mark.sanity
class TestLogin(BaseTestCase):
def test_deploy_new_contract(self):
landing = LandingPage(self.driver)
landing.get_landing_page()
github = landing.login_button.click()
github.sign_in('anna04test',
'f@E23D3H15Rd')
assert github.permission_type.text == 'Personal user data'
bounties_page = github.authorize_sob.click()
github.install_sob_plugin()
assert bounties_page.bounties_header.text == 'Bounties'
assert bounties_page.top_hunters_header.text == 'Top hunters'
github.create_new_bounty()
github.get_deployed_contract()