294 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
			
		
		
	
	
			294 lines
		
	
	
		
			8.8 KiB
		
	
	
	
		
			JavaScript
		
	
	
	
const fs = require('fs')
 | 
						|
const XMLHttpRequest = require('xmlhttprequest').XMLHttpRequest
 | 
						|
const fsp = fs.promises
 | 
						|
const path = require('path')
 | 
						|
const { By, Key, until, Builder, logging, Capabilities } = require('selenium-webdriver')
 | 
						|
const proxy = require('selenium-webdriver/proxy')
 | 
						|
require('chromedriver')
 | 
						|
var chrome = require("selenium-webdriver/chrome");
 | 
						|
const UAALoginPage = require('./pageobjects/UAALoginPage')
 | 
						|
const KeycloakLoginPage = require('./pageobjects/KeycloakLoginPage')
 | 
						|
const assert = require('assert')
 | 
						|
 | 
						|
const runLocal = String(process.env.RUN_LOCAL).toLowerCase() != 'false'
 | 
						|
const uaaUrl = process.env.UAA_URL || 'http://localhost:8080'
 | 
						|
const baseUrl = randomly_pick_baseurl(process.env.RABBITMQ_URL) || 'http://localhost:15672/'
 | 
						|
const hostname = process.env.RABBITMQ_HOSTNAME || 'localhost'
 | 
						|
const seleniumUrl = process.env.SELENIUM_URL || 'http://selenium:4444'
 | 
						|
const screenshotsDir = process.env.SCREENSHOTS_DIR || '/screens'
 | 
						|
const profiles = process.env.PROFILES || ''
 | 
						|
const debug = process.env.SELENIUM_DEBUG || false
 | 
						|
 | 
						|
function randomly_pick_baseurl(baseUrl) {
 | 
						|
    urls = baseUrl.split(",")
 | 
						|
    return urls[getRandomInt(urls.length)]
 | 
						|
}
 | 
						|
function getRandomInt(max) {
 | 
						|
  return Math.floor(Math.random() * max);
 | 
						|
}
 | 
						|
class CaptureScreenshot {
 | 
						|
  driver
 | 
						|
  test
 | 
						|
  constructor (webdriver, test) {
 | 
						|
    this.driver = webdriver
 | 
						|
    this.test = test
 | 
						|
  }
 | 
						|
 | 
						|
  async shot (name) {
 | 
						|
    const image = await this.driver.takeScreenshot()
 | 
						|
    const screenshotsSubDir = path.join(screenshotsDir, this.test)
 | 
						|
    if (!fs.existsSync(screenshotsSubDir)) {
 | 
						|
      await fsp.mkdir(screenshotsSubDir)
 | 
						|
    }
 | 
						|
    const dest = path.join(screenshotsSubDir, name + '.png')
 | 
						|
    await fsp.writeFile(dest, image, 'base64')
 | 
						|
  }
 | 
						|
}
 | 
						|
 | 
						|
module.exports = {
 | 
						|
  log: (message) => {
 | 
						|
    if (debug) console.log(new Date() + " " + message)
 | 
						|
  },
 | 
						|
  error: (message) => {
 | 
						|
    console.error(new Date() + " " + message)
 | 
						|
  },
 | 
						|
  hasProfile: (profile) => {
 | 
						|
    return profiles.includes(profile)
 | 
						|
  },
 | 
						|
 | 
						|
  buildDriver: (url = baseUrl) => {
 | 
						|
    builder = new Builder()
 | 
						|
    if (!runLocal) {
 | 
						|
      builder = builder.usingServer(seleniumUrl)
 | 
						|
    }
 | 
						|
    let chromeCapabilities = Capabilities.chrome();
 | 
						|
    const options = new chrome.Options()
 | 
						|
    chromeCapabilities.setAcceptInsecureCerts(true);  
 | 
						|
    let seleniumArgs = [
 | 
						|
      "--window-size=1920,1080",
 | 
						|
      "--enable-automation",
 | 
						|
      "guest",
 | 
						|
      "disable-infobars",
 | 
						|
      "--disable-notifications",
 | 
						|
      "--lang=en",
 | 
						|
      "--disable-search-engine-choice-screen",
 | 
						|
      "disable-popup-blocking",
 | 
						|
      "--credentials_enable_service=false",
 | 
						|
      "profile.password_manager_enabled=false",
 | 
						|
      "profile.reduce-security-for-testing",
 | 
						|
      "profile.managed_default_content_settings.popups=1",
 | 
						|
      "profile.managed_default_content_settings.notifications.popups=1",
 | 
						|
      "profile.password_manager_leak_detection=false"
 | 
						|
    ]
 | 
						|
    if (!runLocal) {
 | 
						|
      seleniumArgs.push("--headless=new")
 | 
						|
    }
 | 
						|
    chromeCapabilities.set('goog:chromeOptions', {
 | 
						|
      excludeSwitches: [ // disable info bar
 | 
						|
        'enable-automation',
 | 
						|
      ],
 | 
						|
      prefs: {
 | 
						|
        'profile.password_manager_enabled' : false      
 | 
						|
      },
 | 
						|
      args: seleniumArgs
 | 
						|
    });
 | 
						|
    let driver = builder
 | 
						|
      .forBrowser('chrome')
 | 
						|
      //.setChromeOptions(options.excludeSwitches("disable-popup-blocking", "enable-automation"))
 | 
						|
      .withCapabilities(chromeCapabilities)
 | 
						|
      .build()
 | 
						|
    driver.manage().setTimeouts( { pageLoad: 35000 } )
 | 
						|
    return {
 | 
						|
      "driver": driver, 
 | 
						|
      "baseUrl": url
 | 
						|
    }
 | 
						|
  },
 | 
						|
  updateDriver: (d, url) => {
 | 
						|
    return {
 | 
						|
      "driver" : d.driver, 
 | 
						|
      "baseUrl" : url
 | 
						|
    }
 | 
						|
  },
 | 
						|
  getURLForProtocol: (protocol) => {
 | 
						|
 | 
						|
    switch(protocol) {
 | 
						|
      case "amqp": return "amqp://" + hostname
 | 
						|
      default: throw new Error("Unknown prootocol " + protocol)
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  goToHome: (d) => {
 | 
						|
    module.exports.log("goToHome on " + d.baseUrl)
 | 
						|
    return d.driver.get(d.baseUrl)
 | 
						|
  },
 | 
						|
 | 
						|
  goToLogin: (d, token) => {
 | 
						|
    return d.driver.get(d.baseUrl + '#/login?access_token=' + token)
 | 
						|
  },
 | 
						|
 | 
						|
  goToConnections: (d) => {
 | 
						|
    return d.driver.get(d.baseUrl + '#/connections')
 | 
						|
  },
 | 
						|
 | 
						|
  goToExchanges: (d) => {
 | 
						|
    return d.driver.get(d.baseUrl + '#/exchanges')
 | 
						|
  },
 | 
						|
    
 | 
						|
  goToQueues: (d) => {
 | 
						|
    return d.driver.get(d.baseUrl + '#/queues')
 | 
						|
  },
 | 
						|
    
 | 
						|
  goToQueue(d, vhost, queue) {
 | 
						|
    return d.driver.get(d.baseUrl + '#/queues/' + encodeURIComponent(vhost) + '/' + encodeURIComponent(queue))
 | 
						|
  },
 | 
						|
 | 
						|
  delay: async (msec, ref) => {
 | 
						|
    return new Promise(resolve => {
 | 
						|
      setTimeout(resolve, msec, ref)
 | 
						|
    })
 | 
						|
  },
 | 
						|
 | 
						|
  captureScreensFor: (d, test) => {
 | 
						|
    return new CaptureScreenshot(d.driver, require('path').basename(test))
 | 
						|
  },
 | 
						|
 | 
						|
  doUntil: async (doCallback, booleanCallback, delayMs = 1000, message = "doUntil failed") => {
 | 
						|
    let done = false 
 | 
						|
    let attempts = 10
 | 
						|
    let ret
 | 
						|
    do {
 | 
						|
      try {
 | 
						|
        module.exports.log("Calling doCallback (attempts:" + attempts + ") ... ")
 | 
						|
        ret = await doCallback()
 | 
						|
        module.exports.log("Calling booleanCallback (attempts:" + attempts 
 | 
						|
          + ") with arg " + JSON.stringify(ret) + " ... ")
 | 
						|
        done =  booleanCallback(ret)
 | 
						|
      }catch(error) {
 | 
						|
        module.exports.error("Caught " + error + " on doUntil callback...")
 | 
						|
        
 | 
						|
      }finally {
 | 
						|
        if (!done) {
 | 
						|
          module.exports.log("Waiting until next attempt")
 | 
						|
          await module.exports.delay(delayMs)
 | 
						|
        }
 | 
						|
      }     
 | 
						|
      attempts--
 | 
						|
    } while (attempts > 0 && !done)
 | 
						|
    if (!done) {
 | 
						|
      throw new Error(message)
 | 
						|
    }else {
 | 
						|
      return ret
 | 
						|
    }
 | 
						|
  },
 | 
						|
  retry: async (doCallback, booleanCallback, delayMs = 1000, message = "retry failed") => {
 | 
						|
    let done = false 
 | 
						|
    let attempts = 10
 | 
						|
    let ret
 | 
						|
    do {
 | 
						|
      try {
 | 
						|
        module.exports.log("Calling doCallback (attempts:" + attempts + ") ... ")
 | 
						|
        ret = doCallback()
 | 
						|
        module.exports.log("Calling booleanCallback (attempts:" + attempts 
 | 
						|
          + ") with arg " + JSON.stringify(ret) + " ... ")
 | 
						|
        done =  booleanCallback(ret)
 | 
						|
      }catch(error) {
 | 
						|
        module.exports.error("Caught " + error + " on retry callback...")
 | 
						|
        
 | 
						|
      }finally {
 | 
						|
        if (!done) {
 | 
						|
          module.exports.log("Waiting until next attempt")
 | 
						|
          await module.exports.delay(delayMs)
 | 
						|
        }
 | 
						|
      }     
 | 
						|
      attempts--
 | 
						|
    } while (attempts > 0 && !done)
 | 
						|
    if (!done) {
 | 
						|
      throw new Error(message)
 | 
						|
    }else {
 | 
						|
      return ret
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  idpLoginPage: (d, preferredIdp) => {
 | 
						|
    if (!preferredIdp) {
 | 
						|
      if (process.env.PROFILES.includes("uaa")) {
 | 
						|
        preferredIdp = "uaa"
 | 
						|
      } else if (process.env.PROFILES.includes("keycloak")) {
 | 
						|
        preferredIdp = "keycloak"
 | 
						|
      } else {
 | 
						|
        throw new Error("Missing uaa or keycloak profiles")
 | 
						|
      }
 | 
						|
    }
 | 
						|
    switch(preferredIdp) {
 | 
						|
      case "uaa": return new UAALoginPage(d)
 | 
						|
      case "keycloak": return new KeycloakLoginPage(d)
 | 
						|
      default: new Error("Unsupported ipd " + preferredIdp)
 | 
						|
    }
 | 
						|
  },
 | 
						|
  openIdConfiguration: (url) => {
 | 
						|
    const req = new XMLHttpRequest()
 | 
						|
    req.open('GET', url + "/.well-known/openid-configuration", false)
 | 
						|
    req.send()
 | 
						|
    if (req.status == 200) return JSON.parse(req.responseText)
 | 
						|
    else {
 | 
						|
      module.exports.error(req.responseText)
 | 
						|
      throw new Error(req.responseText)
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  tokenFor: (client_id, client_secret, url = uaaUrl) => {
 | 
						|
    const req = new XMLHttpRequest()
 | 
						|
    const params = 'client_id=' + client_id +
 | 
						|
      '&client_secret=' + client_secret +
 | 
						|
      '&grant_type=client_credentials' +
 | 
						|
      '&token_format=jwt' +
 | 
						|
      '&response_type=token'
 | 
						|
 | 
						|
    req.open('POST', url, false)
 | 
						|
    req.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded')
 | 
						|
    req.setRequestHeader('Accept', 'application/json')
 | 
						|
    req.send(params)
 | 
						|
    if (req.status == 200) return JSON.parse(req.responseText).access_token
 | 
						|
    else {
 | 
						|
      module.exports.error(req.responseText)
 | 
						|
      throw new Error(req.responseText)
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  assertAllOptions: (expectedOptions, actualOptions) => {
 | 
						|
    assert.equal(expectedOptions.length, actualOptions.length)
 | 
						|
    for (let i = 0; i < expectedOptions.length; i++) {
 | 
						|
      assert.ok(actualOptions.find((actualOption) =>
 | 
						|
        actualOption.value == expectedOptions[i].value
 | 
						|
          && actualOption.text == expectedOptions[i].text))
 | 
						|
    }
 | 
						|
  },
 | 
						|
 | 
						|
  teardown: async (d, test, captureScreen = null) => {
 | 
						|
    driver = d.driver
 | 
						|
    driver.manage().logs().get(logging.Type.BROWSER).then(function(entries) {
 | 
						|
        entries.forEach(function(entry) {
 | 
						|
          module.exports.log('[%s] %s', entry.level.name, entry.message);
 | 
						|
        })
 | 
						|
     })
 | 
						|
    if (test.currentTest) {
 | 
						|
      if (test.currentTest.isPassed()) {
 | 
						|
        driver.executeScript('lambda-status=passed')
 | 
						|
      } else {
 | 
						|
        if (captureScreen != null) await captureScreen.shot('after-failed')
 | 
						|
        driver.executeScript('lambda-status=failed')
 | 
						|
      }
 | 
						|
    }
 | 
						|
    await driver.quit()
 | 
						|
  },
 | 
						|
 | 
						|
  findTableRow: (table, booleanCallback) => {
 | 
						|
    if (!table) return false
 | 
						|
 | 
						|
    let i = 0
 | 
						|
    while (i < table.length && !booleanCallback(table[i])) i++;      
 | 
						|
    return i < table.length ? table[i] : undefined
 | 
						|
  }
 | 
						|
 | 
						|
}
 |