一.实现方式
python3.7.3+selenium3.141.0
二.目的
1.通过web自动化实现智慧牧场实验案例功能和回归测试。
2.通过开启多个web(模拟多个用户)实现智慧牧场实验案例性能测试,代码放在服务器物理机上运行。服务器配置如下:
三、实现方案
1.web端开启虚拟仿真实验、开启虚拟机容器、打开Thingsboard并创建设备网关
from selenium import webdriver
import requests,json
import os
import xlrd
import time
import paramiko
from selenium.webdriver.support.wait import WebDriverWait
from selenium.webdriver import ActionChains
#获取EXCEL路径
BASE_PATH = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]
EXCEL_PATH = os.path.join(BASE_PATH,'web_aiot','aiot账号密码.xlsx')
#获取table数据
data = xlrd.open_workbook(EXCEL_PATH)
tables = data.sheets()[0]
#获取单元格行数
rows_count = tables.nrows
#获取第一行的列数
cols_count = len(tables.row_values(0))
#行数循环
arr_data1 = []
#driver存储
L = []
for i in range(1,rows_count):
#列数循环
arr_data0 = []
for j in range(0,cols_count):
#获取某一个单元格的内容
row_col_data = tables.cell_value(i,j)
arr_data0.append(str(int(row_col_data)))
arr_data1.append(arr_data0)
try:
#获取token
res_token = requests.post(url='http://aiot.test.nlecloud.com:9190/nledu-cloud-sso-uaa/oauth/token',headers={'Content-Type':'application/x-www-form-urlencoded','Authorization':'Basic bmxlZHUtY2xvdWQtc3NvLXVhYToxMjM0NTY='},data={'grant_type':'password','username':arr_data1[i-1][0],'password':arr_data1[i-1][1]})
token = json.loads(res_token.content)['data']['access_token']
option = webdriver.ChromeOptions()
# 打开调试模式
option.add_argument("--auto-open-devtools-for-tabs")
#selenium打开的浏览器在程序结束时不退出
option.add_experimental_option("detach", True)
option.add_argument('--user-data-dir=C:\\Users\\Administrator\\AppData\\Local\\Google\\Chrome\\User Data' + str(i))
driver = webdriver.Chrome(options=option)
L.append(driver)
driver.get('http://aiot.test.nlecloud.com:9090/sch_edu?token=' + token)
driver.maximize_window()
#点击实验中心按钮
WebDriverWait(driver,20,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/section/head/div[2]/a[2]/span/a'))
time.sleep(1)
driver.find_element_by_xpath('//*[@id="app"]/div/section/head/div[2]/a[2]/span/a').click()
#点击消息动态
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/section/main/div/div[2]/div[2]/div/div[1]/div[2]/ul/li/span[1]'))
time.sleep(0.5)
driver.find_element_by_xpath('//*[@id="app"]/div/section/main/div/div[2]/div[2]/div/div[1]/div[2]/ul/li/span[1]').click()
#点击继续任务
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/section/main/div/div[2]/div[2]/div/div/div[2]/div[2]/div[1]/button/span'))
driver.find_element_by_xpath('//*[@id="app"]/div/section/main/div/div[2]/div[2]/div/div/div[2]/div[2]/div[1]/button/span').click()
#点击虚拟仿真按钮,sleep防止提示任务启动中
time.sleep(1)
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/div/div[2]/div/div/div[2]/div[1]/div[2]/div[2]/img'))
driver.find_element_by_xpath('//*[@id="app"]/div/div/div[2]/div/div/div[2]/div[1]/div[2]/div[2]/img').click()
#点击仿真开启实验按钮
window_handles = driver.window_handles
driver.switch_to_window(window_handles[-1])
#等待+按钮加载完成后再去切换iframe
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="nleEmulator"]/iframe'))
iframe = driver.find_element_by_xpath('//*[@id="nleEmulator"]/iframe')
driver.switch_to.frame(iframe)
#防止页面刷新,找不到按钮元素执行click(),强制睡一会儿,刷新完后再执行元素
WebDriverWait(driver,20,0.5).until(lambda e1: driver.find_element_by_xpath('/html/body/div/section/section/main/div/div/div[1]/div/div[1]/div/div[2]/div/div'))
time.sleep(3)
driver.find_element_by_xpath('/html/body/div/section/section/main/div/div/div[1]/div/div[1]/div/div[2]/div/div').click()
#从frame切换到主文档
driver.switch_to.default_content()
#鼠标移动到+按钮
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]'))
time.sleep(1)
ActionChains(driver).move_to_element(driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]')).perform()
#点击终端按钮
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]/ul/li[1]'))
driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]/ul/li[1]').click()
#print(str(arr_data1[i-1][0])+'web终端已开启',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
#鼠标移动到+按钮
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]'))
time.sleep(1)
ActionChains(driver).move_to_element(driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]')).perform()
#点击thingsboard按钮
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]/ul/li[3]'))
driver.find_element_by_xpath('//*[@id="app"]/div/div/div[1]/div[1]/div[2]/ul/li[3]').click()
#等待frame框架加载完成后再去切换frame
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="app"]/div/div/div[2]/div[3]/iframe'))
iframe = driver.find_element_by_xpath('//*[@id="app"]/div/div/div[2]/div[3]/iframe')
driver.switch_to.frame(iframe)
#等待首页中的设备加载出来
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-home-links/mat-grid-list/div/mat-grid-tile[4]/figure/mat-card/mat-card-content/mat-grid-list/div/mat-grid-tile[1]/figure/a'))
#点击设备
driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-home-links/mat-grid-list/div/mat-grid-tile[4]/figure/mat-card/mat-card-content/mat-grid-list/div/mat-grid-tile[1]/figure/a').click()
time.sleep(2)
#判断网关这一行元素是否存在
flag = True
try:
driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-entities-table/mat-drawer-container/mat-drawer-content/div/div/div/table/tbody/mat-row')
except:
flag = False
if flag == False:
#等待+加载出来
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-entities-table/mat-drawer-container/mat-drawer-content/div/div/mat-toolbar[1]/div/div[2]/button/span[1]/mat-icon'))
time.sleep(1)
#点击+
driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-entities-table/mat-drawer-container/mat-drawer-content/div/div/mat-toolbar[1]/div/div[2]/button/span[1]/mat-icon').click()
#等待添加新设备加载出来
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="mat-menu-panel-1"]/div/button[1]'))
#点击添加新设备
driver.find_element_by_xpath('//*[@id="mat-menu-panel-1"]/div/button[1]').click()
#等待设备名称加载出来
time.sleep(2)
WebDriverWait(driver,10,1).until(lambda e1: driver.find_element_by_xpath('//*[@id="mat-input-15"]'))
#添加设备名称
driver.find_element_by_xpath('//*[@id="mat-input-15"]').send_keys('gateway')
#添加标签
driver.find_element_by_xpath('//*[@id="mat-input-16"]').send_keys('网关')
#点击是网关
driver.find_element_by_xpath('//*[@id="mat-checkbox-4"]/label/div').click()
#点击添加按钮
driver.find_element_by_xpath('//*[@id="mat-dialog-0"]/tb-device-wizard/div/div[4]/button[2]/span[1]').click()
#点击网关这一行
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-entities-table/mat-drawer-container/mat-drawer-content/div/div/div/table/tbody/mat-row'))
driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-entities-table/mat-drawer-container/mat-drawer-content/div/div/div/table/tbody/mat-row').click()
#点击管理凭证
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="mat-tab-content-0-0"]/div/tb-device/div[1]/button[4]/span[1]'))
#防止页面刷新点击不到管理凭证按钮
time.sleep(2)
driver.find_element_by_xpath('//*[@id="mat-tab-content-0-0"]/div/tb-device/div[1]/button[4]/span[1]').click()
#输入访问令牌
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('//*[@id="mat-input-30"]'))
driver.find_element_by_xpath('//*[@id="mat-input-30"]').clear()
driver.find_element_by_xpath('//*[@id="mat-input-30"]').send_keys(arr_data1[i-1][0])
#点击保存
driver.find_element_by_xpath('//*[@id="mat-dialog-1"]/tb-device-credentials-dialog/form/div[3]/button[2]/span[1]').click()
#点击x按钮,返回到设备页面
WebDriverWait(driver,10,0.5).until(lambda e1: driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-entities-table/mat-drawer-container/mat-drawer/div/tb-entity-details-panel/tb-details-panel/header/mat-toolbar/div/button/span[1]/mat-icon'))
driver.find_element_by_xpath('/html/body/tb-root/tb-home/mat-sidenav-container/mat-sidenav-content/div/div/tb-entities-table/mat-drawer-container/mat-drawer/div/tb-entity-details-panel/tb-details-panel/header/mat-toolbar/div/button/span[1]/mat-icon').click()
print(str(arr_data1[i-1][0])+'ThingsBoard已开启',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
except:
print(str(arr_data1[i-1][0])+'web终端开启失败!!!',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
finally:
#从frame切换到主文档,专门为aiot.test.nlecloud.com:9090的record-timestamp使用,而不是TB.目的是防止35分钟后鼠标无操作任务自动退出导致实验停止
driver.switch_to.default_content()
for k in L:
k.execute_script("localStorage.setItem('record-timestamp', new Date().getTime().toString())")
while True:
for k in L:
k.execute_script("localStorage.setItem('record-timestamp', new Date().getTime().toString())")
time.sleep(600)
2.虚拟机中开启智慧牧场实验内容
import requests,json
import os
import xlrd
import time
import paramiko
#获取EXCEL路径
BASE_PATH = os.path.split(os.path.dirname(os.path.abspath(__file__)))[0]
EXCEL_PATH = os.path.join(BASE_PATH,'web_aiot','aiot账号密码.xlsx')
#获取table数据
data = xlrd.open_workbook(EXCEL_PATH)
tables = data.sheets()[0]
#获取单元格行数
rows_count = tables.nrows
#获取第一行的列数
cols_count = len(tables.row_values(0))
#行数循环
arr_data1 = []
for i in range(1,rows_count):
#列数循环
arr_data0 = []
for j in range(0,cols_count):
#获取某一个单元格的内容
row_col_data = tables.cell_value(i,j)
arr_data0.append(str(int(row_col_data)))
arr_data1.append(arr_data0)
try:
#获取token
res_token = requests.post(url='http://aiot.test.nlecloud.com:9190/nledu-cloud-sso-uaa/oauth/token',headers={'Content-Type':'application/x-www-form-urlencoded','Authorization':'Basic bmxlZHUtY2xvdWQtc3NvLXVhYToxMjM0NTY='},data={'grant_type':'password','username':arr_data1[i-1][0],'password':'123456'})
token = json.loads(res_token.content)['data']['access_token']
#print(token)
#获取最新的学生实验任务id
task_id = requests.get(url='http://52.130.248.0:9191/api-teaching/student/tasks/own/list?isReport=false',headers={'Content-Type':'application/x-www-form-urlencoded','Authorization':'bearer' + ' ' + token})
id = json.loads(task_id.content)['data'][0]['id']
#print(json.loads(task_id.content))
#开启容器,并获取容器id
res_container = requests.put(url='http://52.130.248.0:9191/api-teaching/student/tasks/do/start/' + id + '?ports=:22,:20805,:20905&type=2',headers={'Authorization':'bearer' + ' ' + token})
container_id = json.loads(res_container.content)['data']
# 获取容器的状态
container_status = 'Creating'
while container_status != 'Running':
time.sleep(5)
res_container = requests.get(url='http://52.130.248.0:9191/api-teaching/containers/detail?id=' + str(container_id),headers={'Authorization':'bearer' + ' ' + token})
container = json.loads(res_container.content)
container_status = container['data']['container']['state']
if i == 1:
ip1 = container['data']['virtualMachine']['ip']
print('主虚拟机已开启')
else:
publicIp = container['data']['virtualMachine']['publicIp']
#连接虚拟机
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(publicIp,'端口号','账号','密码')
stdin, stdout, stderr = ssh.exec_command('ls')
content = stdout.read().decode()
if content == '':
stdin, stdout, stderr = ssh.exec_command('cmd=`cat /etc/profile|grep docEnv|head -1|sed \"s/\'//g\"`;$cmd;echo $docEnv;wget https://newlandblob.blob.core.chinacloudapi.cn/test/chirpstack-docker-cn.tgz;tar -zxf chirpstack-docker-cn.tgz;sed -i "s/d1-cdn.alpinelinux.org/mirrors.aliyun.com/g" /etc/apk/repositories;apk add sshpass;sshpass -p 密码 scp -r -P 10001 -o StrictHostKeyChecking=no root@' + ip1 + ':/root/chirpstack-docker-cn/data /root/chirpstack-docker-cn;cd chirpstack-docker-cn;docker-compose up -d')
stdout.channel.set_combine_stderr(True)
output = stdout.readlines()
else:
stdin, stdout, stderr = ssh.exec_command('cmd=`cat /etc/profile|grep docEnv|head -1|sed \"s/\'//g\"`;$cmd;echo $docEnv;cd chirpstack-docker-cn;docker-compose down;docker-compose up -d')
stdout.channel.set_combine_stderr(True)
output = stdout.readlines()
ssh.close()
#等待chirpstack启动完成
time.sleep(10)
#登录获取chirpstack token,需要公网ip
res_token = requests.post(url='http://' + publicIp + ':10002/api/internal/login',headers={'Content-Type':'application/json'},data=json.dumps({'email':'admin','password':'admin'}))
token = json.loads(res_token.content)['jwt']
#更新thingsboard网关设备Token
tb = requests.put(url='http://' + publicIp + ':10002/api/applications/1/integrations/thingsboard',headers={'Content-Type':'application/json','Grpc-Metadata-Authorization':'Bearer' + ' ' + token},data=json.dumps({"integration": {"applicationID": "1","server": "{\"Server\":\"52.130.177.111:1883\",\"Token\":\"" + str(arr_data1[i-1][0]) + "\"}","thingsboard_token": str(arr_data1[i-1][0])}}))
print(str(arr_data1[i-1][0])+ '已完成容器启动',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
except:
print(str(arr_data1[i-1][0])+ '容器启动失败!!!',time.strftime("%Y-%m-%d %H:%M:%S", time.localtime()))
四.代码地址
https://github.com/songteng2012/aiotcloud