Requested operation is not valid: network 'default' is not active

本文介绍了一种在KVM环境下启动虚拟机时遇到的网络问题及其解决方案。通过激活默认网络,解决了虚拟机无法启动的问题。

我在安装KVM时并没有进行网络配置。安装完成并且添加虚拟机后,在启动虚拟机是出现了如下问题:

Requested operation is not valid: network 'default' is not active

解决方案:

virsh net-autostart default
virsh net-start default
再次开启虚拟机,问题解决。
握手和证书验证在httpd模块请求入口那里就已经实现了对https的处理,这里是不是可以不用修改?基本上只要考虑事件推送pull point和basic notify相关,基于我前面给你的onvif协议上对此的规范,能不能重新给出完整的修改,分步骤,对每一步修改繇指出是根据协议规范上的哪一点来修改的?原因是什么?怎么修改?请根据协议重新对soap_tev.c和soap_event.c的代码进行修改——Real-time Pull-Point Notification Interface This section introduces the Real-time Pull-Point Notification Interface. This interface provides a firewall friendly notification interface that enables real-time polling and initiates all client communications. This interface is used in the following way: The client asks the device for a pull point with the CreatePullPointSubscriptionRequest message. The device evaluates the subscription request and returns either a CreatePullPointSubscriptionResponse or one of the Fault codes. If the subscription is accepted, the response contains a WS-EndpointReference to the instantiated pull point. This WS-Endpoint provides a PullMessages operation, which is used by the client to retrieve Notifications. Additionally it provides the Renew and Unsubscribe operations of the Base Subscription Manager Interface. The sequence diagram of the interaction is shown in Figure 6. Client Event Service CreatePullPoint SubscriptionRequest Instantiate CreatePullPoint SubscriptionResponse PullMessages Request PullPoint PullMessages Response Unsubscribe Request Unsubscribe Response Figure 6: Sequence diagram for the Real-time Pull-Point Notification Interface The device immediately responds with notifications that have been aggregated on behalf of the client. If there are no aggregated notifications, the device waits to respond until either a notification is produced for the client or the specified Timeout has exceeded. In any case, the response will contain, at most, the number of notifications specified by the MessageLimit parameter. The client can poll the notifications in real-time when it starts a new PullMessagesRequest immediately after each PullMessagesResponse. For a device implementation it is important to support multiple pull points (including multiple pullpoints per client) in order to allow precise event generation. If a device would only support one subscription at a time a client would need to subscribe without any scope restriction, because changing of event subscription is not possible. Hence this would require the device to serve all available events for which the device would have to activate all subsystems that generate events. This may cause unnecessary load by e.g. activating multiple motion detectors and similar without need. Additionally the traffic produced by all these events may cause a substantial network load. ONVIF™– 86 ONVIF Core Spec – Ver. 24.12 If the device supports persistent notification storage, see 9.1.7, the WS-Endpoint also provides a Seek opera tion. This operation allows to reposition the pull pointer into the past. With the Seek operation it is also possible to reverse the pull direction. There is also a BeginOfBuffer event, as defined in 9.11.1, that signals the start of the buffer. An ONVIF compliant device shall implement the Real Time Pull-Point Notification Interface. 9.1.1 Create pull point subscription An ONVIF compliant device shall provide the CreatePullPointSubscription command. If no Filter element is specified the pullpoint shall notify all occurring events to the client. By default the pull point keep alive is controlled via the PullMessages operation. In this case, after a PullMes sages response is returned, the subscription should be active for at least the timeout specified in the PullMes sages request. A device shall support an absolute time value specified in utc as well as a relative time value for the InitialTer minationTime parameter. A device shall respond both parameters CurrentTime and TerminationTime as utc using the ‘Z’ indicator. The following optional subscription policy elements are defined in tev:SubscriptionPolicy: • tev:ChangedOnly A pullpoint should not provide Initialized nor Deleted events for Properties. Both request and response message contain the same elements as the SubscriptionRequest and Response of [WS-BaseNotification] without the ConsumerReference. REQUEST: • Filter - optional [wsnt:FilterType] Optional filtering for e.g. topics. • InitialTerminationTime - optional [wsnt:AbsoluteOrRelativeTimeType] Initial termination time. • SubscriptionPolicy - optional [xs:any] RESPONSE: • SubscriptionReference [wsa:EndpointReferenceType] Endpoint reference of the subscription to be used for pulling the messages. • CurrentTime [xs:dateTime] Current time of the server for synchronization purposes. • TerminationTime [xs:dateTime] Date time when the PullPoint will be shut down without further pull requests. FAULTS: • The same faults as for Subscription Request of the [WS-BaseNotification] are used. ACCESS CLASS: READ_MEDIA 9.1.2 Pull messages The device shall provide the following PullMessages command for all SubscriptionManager endpoints returned by the CreatePullPointSubscription command. ONVIF™– 87 ONVIF Core Spec – Ver. 24.12 The device shall support a Timeout of at least one minute. The device shall not respond with a PullMessages FaultResponse when the MessageLimit is greater than the device supports. Instead, the device shall return up to the supported messages in the response. The response behavior shall be one of three types: • If there are one or more messages waiting (i.e., aggregated) when the request arrives, the device shall immediately respond with the waiting messages, up to the MessageLimit. The device shall not discard unsent messages, but shall await the next PullMessages request to send remaining messages. • If there are no messages waiting, and the device generates a message (or multiple simultaneous messages) prior to reaching the Timeout, the device shall immediately respond with the generated messages, up to the MessageLimit. The device shall not wait for additional messages before returning the response. • If there are no messages waiting, and the device does not generate any message prior to reaching the Timeout, the device shall respond with zero messages. The device shall not return a response with zero messages prior to reaching the Timeout. A device shall respond both parameters CurrentTime and TerminationTime as utc using the ‘Z’ indicator. After a seek operation the device shall return the messages in strict message utc time order. Note that this requirement is not applicable to standard realtime message delivery where the delivery order may be affected by device internal computations. A device should return an error (UnableToGetMessagesFault) when receiving a PullMessages request for a subscription where a blocking PullMessage request already exists. REQUEST: • Timeout [xs:duration] Maximum time to block until this method returns. • MessageLimit [xs:int] Upper limit for the number of messages to return at once. A server implementation may decide to return less messages. RESPONSE: • CurrentTime [xs:dateTime] The date and time when the messages have been delivered by the web server to the client. • TerminationTime [xs:dateTime] Date time when the PullPoint will be shut down without further pull requests. • NotificationMessage - optional, unbounded [wsnt:NotificationMessageHolderType] List of messages. This list shall be empty in case of a timeout. PULLMESSAGESFAULTRESPONSE: • MaxTimeout [xs:duration] Only when the Timeout exceeds the upper limit supported by the device. Not sent when the Message Limit is exceeded. The Fault Message shall contain the upper limits for both parameters. • MaxMessageLimit [xs:int] FAULTS: • No specific fault codes. ACCESS CLASS: READ_MEDIA ONVIF™– 88 ONVIF Core Spec – Ver. 24.12 9.1.3 Renew An ONVIF compliant device shall support this command if it signals support for [WS-Base Notification] via the MaxNotificationProducers capability. The command shall at least support a Timeout of one minute. A device shall respond both parameters Cur rentTime and TerminationTime as utc using the ‘Z’ indicator. REQUEST: • TerminationTime [wsnt:AbsoluteOrRelativeTimeType] The new relative or absolute termination time. RESPONSE: • CurrentTime [xs:dateTime] The current server time. • TerminationTime [xs:dateTime] The updated TerminationTime for the SubscriptionManager. RESOURCEUNKNOWNFAULTRESPONSE: • Timestamp [xs:dateTime] The pull point reference is invalid • Originator - optional [wsa:EndpointReferenceType] • ErrorCode - optional [xs:any] UNACCEPTABLETERMINATIONTIMEFAULTRESPONSE: • Timestamp [xs:dateTime] The Timeout exceeds the upper limit supported by the device. • Originator - optional [wsa:EndpointReferenceType] • ErrorCode - optional [xs:any] FAULTS: • No specific fault codes. ACCESS CLASS: READ_MEDIA 9.1.4 Unsubscribe The device shall provide the following Unsubscribe command for all SubscriptionManager endpoints returned by the CreatePullPointSubscription command. The command is defined in section 6.1.2 of [OASIS Web Ser vices Base Notification 1.3 [http://docs.oasis-open.org/wsn/wsn-ws_base_notification-1.3-spec-os.pdf]]. This command shall terminate the lifetime of a pull point. REQUEST: This is an empty message. RESPONSE: This is an empty message. ONVIF™– 89 ONVIF Core Spec – Ver. 24.12 RESOURCEUNKNOWNFAULTRESPONSE: • Timestamp [xs:dateTime] The pull point reference is invalid • Originator - optional [wsa:EndpointReferenceType] • ErrorCode - optional [xs:any] FAULTS: • No specific fault codes. ACCESS CLASS: READ_MEDIA 9.1.5 Seek A device supporting persistent notification storage as defined in section 9.1.7 shall provide the following Seek command for all SubscriptionManager endpoints returned by the CreatePullPointSubscription command. On a Seek a pullpoint shall abort any event delivery including any initial states of properties. Furthermore the pullpoint should flush events not already queued for transmission from the transmit queue. After a Seek request a pullpoint shall ignore the behavior described in section 9.6 for properties. A device shall only set the subscription in reverse pull mode if the Reverse argument is present and set to “true”. The UtcTime argument of the Seek request shall be matched against the UtcTime attribute of the notifications in the persistent notification storage. When Seek is used in the forward mode a device shall position the pull pointer to include all NotificationMes sages in the persistent storage with a UtcTime attribute greater than or equal to the Seek argument. When Seek is used in reverse mode a device shall position the pull pointer to include all NotificationMessages in the in the persistent storage with a UtcTime attribute less than or equal to the Seek argument. A device shall not provide information of the initial generate property state as response to a call to the Seek method. REQUEST: • UtcTime [xs:datetime] This message shall be addressed to a PullPoint in order to readjust the pull position: • Reverse - optional [xs:bool] RESPONSE: This is an empty message. FAULTS: • No specific fault codes. ACCESS CLASS: READ_MEDIA 9.1.6 Pull Point Lifecycle Figure 6 depicts the basic operation of a pull point. This chapter states the requirements on the pull point lifecycle. ONVIF™– 90 ONVIF Core Spec – Ver. 24.12 A device shall create a new pull point on each CreatePullPointSubscription command as long as the number of instantiated pull points does not exceed the capability MaxPullPoints. Each pull point shall have a unique endpoint reference to which the client can direct its consecutive operations on the pull point. A pull point shall exist until either its termination time has elapsed or the client has requested its disposal via an Unsubscribe request. There are no requirements regarding persistency of a pull point across a power cycle of a device. 9.1.7 Persistent notification storage To ensure that no notifications are lost by a client a device may store its notifications. The stored notifications can at any time be retrieved by a client. The device shall indicate if its support persistent notification storage with the PersistentNotificationStorage capability. See section 9.8. This specification defines that the interface to the persistent storage allows linear access via the originating message event time. This holds also for events that are delivered out of order in the live streaming case due to e.g. computational delay. The details of what notification and how and where those notifications actually are stored are outside the scope of this specification. Removal policy of stored notifications to get room for new ones is also out of scope. 9.2 Notification Streaming Interface This section defines the transmission of events via RTP streaming packets. For details regarding the configu ration see section “Metadata Configuration“ of the ONVIF Media Service Specification. The following requirements apply if a devices supports transmission of events via RTP streaming packets: • The events shall be encoded as wsnt:NotificationMessage as defined in [WS-BaseNotification] to trans port the Message Payload, the Topic and the ProducerReference. • Multiple instances of the wsnt:NotificationMessage elements can be placed within a metadata docu ment. • Since there is no explicit SubscriptionReference with streaming notifications, the wsnt:NotificationMes sage shall not contain the SubscriptionReference element. 9.3 Basic Notification Interface Section 9.3.1 briefly introduces the Basic Notification Interface of the [WS-BaseNotification] specification. Sec tion 9.3.2 summarizes the mandatory and the optional interfaces of the [WS-BaseNotification] specification. Please refer for a full documentation of the Basic Notification Interface to the [WS-BaseNotification] specifica tion. 9.3.1 Introduction The following logical entities participate in the notification pattern: Client: implements the NotificationConsumer interface. Event Service: implements the NotificationProducer interface. Subscription Manager: implements the BaseSubscriptionManager interface. The Event Service and the Subscription Manager should be instantiated on a device. Typical messages exchanged between the entities are shown in the sequence diagram in Figure 7. First, the client establishes a connection to the Event Service. The client can then subscribe for certain notifications by sending a SubscriptionRequest. If the Event Service accepts the Subscription, it dynamically instantiates a SubscriptionManager representing the Subscription. The Event Service shall return the WS-Endpoint-Address of the SubscriptionManager in the SubscriptionResponse. ONVIF™– 91 ONVIF Core Spec – Ver. 24.12 In order to transmit notifications matching the Subscription, another connection is established from the Event Service to the client. Via this connection, the Event Service sends a one-way Notify message to the Notifica tionConsumer interface of the client. Corresponding notifications can be sent at any time by the Event Service to the client, while the Subscription is active. To control the Subscription, the client directly addresses the SubscriptionManager returned in the Subscrip tionResponse. In the SubscriptionRequest the client can specify a termination time. The SubscriptionManager is automatically destroyed when the termination time is reached. RenewRequests can be initiated by the client in order to postpone the termination time. The client can also explicitly terminate the SubscriptionManager by sending an UnsubscribeRequest. After a successful Unsubscription, the SubscriptionManager no longer exists. The interaction between EventService and SubscriptionManager is not further specified by the [WS-BaseNo tification] and is up to the implementation of the device. Client Event Service SubscriptionRequest Instantiate SubscriptionResponse Notify RenewRequest RenewResponse Subscription Manager Notify UnsubscribeRequest UnsubscribeResponse Figure 7: Sequence diagram for the Base Notification Interface 9.3.2 Requirements This section details those interfaces of the [WS-BaseNotification] that a device shall provide. An ONVIF compliant device shall support the NotificationProducer Interface of the [WS-BaseNotification] if the capability MaxNotificationProducers is non-zero. The device shall support TopicExpression filters with the dialects described in 9.6.3. The support for MessageContent filters is signalled via the GetEventProperties method. If the device does not accept the InitialTerminationTime of a subscription, it shall provide a valid Ini tialTerminationTime within the Fault Message. The device shall be able to provide notifications using the Noti fy wrapper of the [WS-BaseNotification] specification. The SubscriptionPolicy wsnt:UseRaw is optional for the device. Although the [WS-BaseNotification] has CurrentTime and TerminationTime as optional elements in a SubscribeResponse and RenewResponse, an ONVIF compliant device shall list them in both SubscribeRe sponses and RenewResponse. The device may respond to any GetCurrentMessage request with a Fault mes sage indicating that no current message is available on the requested topic. An ONVIF compliant device shall implement the Base Subscription Manager Interface of the [WS-BaseNotifi cation] specification consisting of the Renew and Unsubscribe operations. The Pausable Subscription Manager Interface is optional. The implementation of Subscriptions as WS-Resources is optional. ONVIF™– 92 ONVIF Core Spec – Ver. 24.12 An ONVIF compliant device shall support time values in request parameters that are given in utc with the ‘Z’ indicator and respond all time values as utc including the ‘Z’ indicator
10-10
#!/usr/bin/env python import datetime # -*- coding: UTF-8 -*- import subprocess import time import sys import os import json import requests import logging import HTTP_Requests as hr import Response_Processing as rp import Static_Functions as sf import Excel_Operator as eo import openpyxl # try: # from . import RSAEncrypt # except: import RSAEncrypt class HTTP(): def __init__(self, ip=None, username=None, password=None): self.logger = logging.getLogger(self.__class__.__name__) # print(self.__class__.__name__()) self.ip=ip self.username=username self.password=password self.stok = None self.cookie = None self.login_status = False # dut对象记录所有测试结果的列表 self.test_results = [] # 创建dut对象的Excel工作簿对象 self.wb = openpyxl.Workbook() # 添加一个工作表 self.ws = self.wb.active self.ws.title = '测试结果' self.headers = {"Host": "%s" % self.ip, "Connection": "keep-alive", "Accept": "application/json, text/javascript, */*; q=0.01", "Origin": "http://%s" % self.ip, # "X-Requested-With": "XMLHttpRequest", "User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) " "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "http://%s/webpages/login.html" % self.ip, "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.8", "cookie": None } # 先将样机webserver状态设置为False self.webserver_status = False # 再调用http_request_init()检查样机webserver状态并登陆获取stok和cookie self.http_request_init() def _post_model_form_data(self, model_name=None, form_name=None, data=None): # used by other function to post the whole data to the dut self.logger.info(' start _post_model_form_data ') submit_data = { "module": model_name, "form": form_name, "data": data } self.logger.info('_post_model_form_data Post data is %s' % submit_data) output = self.http_request_op(submit_data) return output def http_request_op(self, submit_data=None): maxtrytime = 3 sleep_time = 1 connection_interval = 3 for item in range(1, maxtrytime): try: time.sleep(sleep_time) if sleep_time != 1: self.logger.debug('************** try to post data %s times **************' % item) resp_dict = self._http_request_op(submit_data=submit_data) return resp_dict except ValueError as ex: raise ValueError('Post data form error, web server code= %s' % ex) except RuntimeError: sleep_time += connection_interval if item < maxtrytime: continue except requests.exceptions.ConnectionError: sleep_time += connection_interval if item < maxtrytime: continue else: self.logger.error('Connection error') except requests.exceptions.HTTPError: sleep_time += connection_interval if item < maxtrytime: continue else: self.logger.error('HTTP error') raise Exception(f'Post data error, submit_data is {submit_data}') def _http_request_op(self, submit_data=None): retry = 1 while not self.login_status: self.http_request_init() if self.login_status: self.logger.info('Login dut success!') break self.logger.warning('Login failed, Retry to login, times=%s' % retry) if retry >= 5: raise RuntimeError("Login %s failed" % self.ip) retry += 1 time.sleep(3) # separators参数的作用是去掉,:后面的空格 raw_data = json.dumps(submit_data['data'], ensure_ascii=False, separators=(',', ':')) form_raw = {"data": raw_data} url = "http://%s/cgi-bin/luci/;stok=%s/admin/%s?form=%s" % ( self.ip, self.stok, submit_data['module'], submit_data['form']) self.logger.debug("[+] url (%s)" % url) try: resp = requests.post(url=url, data=form_raw, headers=self.headers, timeout=30) self.logger.debug("Post data function success") #首先检查页面状态码是否为200 if resp.status_code == 200: js = json.loads(resp.content) time.sleep(0.2) # 检查页面响应错误码是否为0 if str(js['error_code']) == '0': self.logger.debug('Post data form success!') return js # 检查页面响应错误码不为0时,在发送一次请求 else: self.logger.debug('*******************页面错误码不为0,再次尝试登陆****************************') self.http_request_init() time.sleep(3) resp2 = requests.post(url=url, data=form_raw, headers=self.headers, timeout=30) if resp2.status_code == 200: js2 = json.loads(resp2.content) time.sleep(0.2) # 检查页面响应错误码是否为0 if str(js2['error_code']) == '0': self.logger.debug('Post data form success!') self.logger.debug('js2 is %s' % js2) return js2 else: raise RuntimeError('Web server return error, error code = %d' % js2['error_code']) else: raise RuntimeError('Web server return error, http code = %d' % resp2.status_code) else: raise RuntimeError('Web server return error, http code = %d' % resp.status_code) except requests.exceptions.HTTPError as ex: self.logger.error('Post data form failed! Http error:%s' % ex) raise ex except requests.exceptions.URLRequired as ex: self.logger.error('Post data form failed! Url error:%s' % ex) raise ex except Exception as ex: self.logger.error('Post data form failed! Unkonwn error:%s' % ex) raise ex def check_server_open(self): headers_of_check_server_open = {"Host": "%s" % self.ip, "Connection": "keep-alive", "Accept": "application/json, text/javascript, */*; q=0.01", "Origin": "http://%s" % self.ip, "X-Requested-With": "XMLHttpRequest", "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "http://%s/webpages/login.html" % self.ip, "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.8" } url_of_check_server_open = "http://%s/webpages/login.html" % self.ip try: resp = requests.get(url=url_of_check_server_open, headers=headers_of_check_server_open, timeout=30) if resp.status_code == 200: self.webserver_status = True except Exception: # 此处用于尝试重新发送请求检查webserver状态: retry_times = 5 self.logger.debug("即将开始重新尝试,retry_times =" + str(retry_times)) while ((self.webserver_status == False) and (retry_times >= 1)): try: resp2 = requests.get(url=url_of_check_server_open, headers=headers_of_check_server_open, timeout=30) if resp2.status_code == 200: self.webserver_status = True print('----------------------------------------重新连接webserver成功,确认样机webserver已开启') except: retry_times = retry_times - 1 print('----------------------------------------尝试第" + str(5 - retry_times) + "次连接样机失败,请检查样机状态') time.sleep(0.7) def http_request_init(self): self.check_server_open() # webserver状态检查函数 print(f'----------------------------------------样机webserver状态为{self.webserver_status}') if self.webserver_status == True: # webserver状态检查成功,进入样机是否为出厂设置检查分支 self.check_status = '' # check_status来储存样机是否处于默认出厂状态 self.check_status = self.check_status_and_set_password() self.check_status = self.check_status.lower() # 全小写避免样机差异,default代表处于默认出厂状态,modify代表已经被设置 # print('----------------------------------check_status=' + str(self.check_status)) # 其实是三个分支 if self.check_status == ('default'): self.logger.info('----------------------------------------检查到样机的状态为默认的出厂设置') self.mark_password = self.password # 用于记录用户设定的密码,然后在后面的set_new_password时传入 self.password = 'admin' self.get_stok_cookie_by_password() # 包含了get uptime算密码的逻辑,但是算之前先把self.password设置为admin self.set_new_password() print('----------------------------------------出厂状态下,样机设置密码成功') self.password = self.mark_password self.get_stok_cookie_by_password() # 设定新密码后重新登录拿cookie和stok self.login_status = True # headers添加cookie self.headers["cookie"] = self.cookie print('----------------------------------------出厂状态下,样机登录成功') if self.check_status == ('modify'): self.get_stok_cookie_by_password() self.login_status = True # headers添加cookie self.headers["cookie"] = self.cookie print('----------------------------------------已修改密码状态下,样机登陆成功') else: print('----------------------------------------样机webserver未开启,请检查样机状态后重新实例化ERRouter_int类') def check_status_and_set_password(self): headers_of_check_status_and_set_password = { "Host": "%s" % self.ip, "Connection": "keep-alive", "Accept": "application/json, text/javascript, */*; q=0.01", "Origin": "http://%s" % self.ip, "X-Requested-With": "XMLHttpRequest", "User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) " "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "http://%s/webpages/login.html" % self.ip, "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.8" } post_data_of_check_status_and_set_password = {"data": '{"method":"get"}'} url_of_check_status_and_set_password = 'http://%s/cgi-bin/luci/;stok=/userconfig?form=cfg_save' % self.ip resp = requests.post(url=url_of_check_status_and_set_password, data=post_data_of_check_status_and_set_password, headers=headers_of_check_status_and_set_password) time.sleep(0.5) if resp.status_code == 200: js = json.loads(resp.content) time.sleep(0.2) if str(js['error_code']) == '0': return js['result']['config_status'] else: print('----------------------------------------检查样机是否为出厂设置状态失败,error_code=%s' % str(js['error_code'])) time.sleep(0.2) return '----------------------------------------获取dut状态失败,错误位于【error_code】,可能与post表单格式有关' else: print('----------------------------------------检查样机是否为出厂设置状态失败,http 响应 status_code=%s' % str(resp.status_code)) time.sleep(0.2) return '----------------------------------------获取dut状态失败,错误位于【http 响应 status_code】,可能与url和headers有关' def get_stok_cookie_by_password(self): # get_stok_cookie_by_password()这个函数会自己去得到uptime然后计算加密,但是为了方便维护,把算密码和加密分开写 _uptime = self.get_uptime() # get_uptime()和get_encrypt_password()都会return相应值 time.sleep(2) finaly_password = self.get_encrypt_password(up_time=_uptime) post_data_of_get_stok_cookie_by_password = { "data": '{"method":"login","params":{"username":"admin","password":"%s"}}' % finaly_password } headers_of_get_stok_cookie_by_password = { "Host": "%s" % self.ip, "Connection": "keep-alive", "Accept": "application/json, text/javascript, */*; q=0.01", "Origin": "http://%s" % self.ip, "X-Requested-With": "XMLHttpRequest", "User-Agent": "Mozilla/5.0 (Windows NT 6.3; WOW64) " "AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36", "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8", "Referer": "http://%s/webpages/login.html" % self.ip, "Accept-Encoding": "gzip, deflate", "Accept-Language": "zh-CN,zh;q=0.8" } url_of_get_stok_cookie_by_password = "http://%s/cgi-bin/luci/;stok=/login?form=login" % self.ip resp = requests.post(url=url_of_get_stok_cookie_by_password, data=post_data_of_get_stok_cookie_by_password, headers=headers_of_get_stok_cookie_by_password) try: print('----------------------------------------正在获取cookie与stok......') resp_dict = json.loads(resp.content) self.stok = resp_dict['result']['stok'] # print(f'resp_dict is {resp_dict}') self.cookie = resp.cookies self.cookie = str(self.cookie) # print(self.cookie) self.cookie = self.cookie.split(' ')[1] print("----------------------------------------得到登录的cookie与stok分别为") print(f'----------------------------------------cookie:{self.cookie}') print(f'----------------------------------------stok:{self.stok}\n') return [self.cookie, self.stok] except Exception as ex: self.logger.warning("样机处于非出厂设置状态,用户名密码不正确,请重新检查用户名密码或恢复出厂设置后重新实例化ERRouter_int()类") raise ex def get_uptime(self): headers_of_get_uptime = { 'Host': "%s" % self.ip, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Accept-Encoding': 'gzip, deflate', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest', 'Content-Length': '14', 'Origin': 'http://%s' % self.ip, 'Connection': 'keep-alive', 'Referer': 'http://%s/webpages/login.html' % self.ip, 'Pragma': 'no-cache', 'Cache-Control': 'no-cache' } url_of_get_uptime = 'http://%s/cgi-bin/luci/;stok=/locale?form=lang' % self.ip post_data_of_get_uptime = {"operation": "read"} req2 = requests.post(url=url_of_get_uptime, data=post_data_of_get_uptime, headers=headers_of_get_uptime) st = req2.content resp_dict = json.loads(st) if 'uptime' in list(resp_dict['result'].keys()): up_time = resp_dict['result']['uptime'] print('----------------------------------------获取到登录加密的up_time的值为: ' + str(up_time)) return str(up_time) else: print('----------------------------------------该机型登录机制未加时间戳' ) return None def get_encrypt_password(self, up_time=None): if up_time is not None: _password_with_uptime = self.password + '_' + up_time else: _password_with_uptime = self.password _encrypt_password = RSAEncrypt.Encrypt(_password_with_uptime) # print('----------------------------------加密后密码为' + str(_encrypt_password)) return _encrypt_password def set_new_password(self): old_acc = 'admin' old_pwd = '21dd905725bef0483f91a45c954f26dd0c6640329cf266f043d8a386855b22d2e056c' \ '0411a8f6246fcbb8e1804a5d433a92334b312a403616eb03ac17051a3f903f39c92a7' \ 'e512fe5b8deac4e455fbe532cd919749a75ebf8e3ed0927cf5277c2d0304478a54efa' \ 'aa1ecd05d1b760473e6bd06734075b6040998d77ee59d87bf' new_acc = 'admin' new_pwd = RSAEncrypt.Encrypt(self.mark_password) post_data = \ { "method": "set", "params": { "old_acc": old_acc, "old_pwd": old_pwd, "new_acc": new_acc, "new_pwd": new_pwd, "cfm_pwd": new_pwd, } } data_raw = json.dumps(post_data, separators=(',', ':')) post_data_of_set_new_password = {"data": data_raw} time.sleep(1) url_of_set_new_password = 'http://%s/cgi-bin/luci/;stok=%s/admin/administration?form=accountfirstset' % ( self.ip, self.stok) headers_of_set_new_password = { "Host": "%s" % self.ip, 'User-Agent': 'Mozilla/5.0 (Windows NT 10.0; Win64; x64; rv:109.0) Gecko/20100101 Firefox/113.0', 'Accept': 'application/json, text/javascript, */*; q=0.01', 'Accept-Language': 'zh-CN,zh;q=0.8,zh-TW;q=0.7,zh-HK;q=0.5,en-US;q=0.3,en;q=0.2', 'Accept-Encoding': 'gzip, deflate', 'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8', 'X-Requested-With': 'XMLHttpRequest', 'Content-Length': '14', "Origin": "http://%s" % self.ip, 'Connection': 'keep-alive', "Referer": "http://%s/webpages/login.html" % (self.ip), 'Pragma': 'no-cache', 'Cache-Control': 'no-cache', 'Cookie': '%s' % self.cookie } resp = requests.post(url=url_of_set_new_password, data=post_data_of_set_new_password, headers=headers_of_set_new_password) try: js = json.loads(resp.content) time.sleep(0.2) if str(js['error_code']) == '0': print('----------------------------------------设置密码' + self.mark_password + "成功") except Exception: self.logger.warning("设定密码时失败,请检查样机连接状态") #************************************************************************************************************************************************************************************************************************************* # ************************************************************************************************************************************************************************************************************************************* # ************************************************************************************************************************************************************************************************************************************* # ************************************************************************************************************************************************************************************************************************************* # ************************************************************************************************************************************************************************************************************************************* # def add_lan_network(self): # post_data = {"method": "add", "params": {"index": 1, "old": "add", # "new": {"default": "0", "name": "LAN2", "ipaddr": "192.168.2.1", # "netmask": "255.255.255.0", "mode": "normal", # "isolation": "off", "vlanid": "2", "igmp_snooping": "", # "dhcp_mode": "dhcp_server", "enable": "on", # "ipaddr_start": "192.168.2.100", "ipaddr_end": "192.168.2.199", # "leasetime": "120", "gateway": "", "domain": "", "pri_dns": "", # "snd_dns": "", "next_server": "", "option42": "", # "option67": "", "option2": "", "option66": "", "option252": "", # "option60": "", "option138": "", "option150": "", # "option159": "", "option160": "", "option176": "", # "option242": "", "relay_enable": "off", "dhcp_opts": []}, # "vlanid": "add"}} # self.output = self._post_model_form_data(model_name='dhcps', form_name='lan', data=post_data) # print(f'{self.output}') def BasicTest_NetworkAttach(self): self.network_mode_names = { 'prefer_lte': '4G优先', 'only_lte': '仅4G', 'only_wcdma': '仅3G' # 后续添加5G相关内容 } post_data = {"method":"get"} resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) self.LTE_Result = rp.parse_lte_status(resp) Roaming = self.LTE_Result['数据漫游开关-data_roaming'] ISP = self.LTE_Result['当前运营商-current_operator'] self.preferred_network_type = self.LTE_Result['可用网络模式列表-available_network_modes'] self.Default_Network_Type = self.preferred_network_type[0] self.Default_Profile_name = self.LTE_Result['配置文件名称-profile_name'] print(f'----------------------------------------以下是SIM1卡槽对应拨号信息,请确保SIM卡插在SIM1卡槽!!!\n{self.LTE_Result}') print(f'----------------------------------------其中漫游状态:{Roaming},服务提供商:{ISP}') print(f'----------------------------------------拨号成功,接下来是网络连通性测试') sf.quick_internet_test() print('\n\n\n') def BasicTest_NetworkSwitch(self): # 直接使用了BasicTest_NetworkAttach中的self.LTE_Result参数,所以再运行此用例前必须先运行BasicTest_NetworkAttach print(f'----------------------------------------当前机型支持的网络模式有:{self.preferred_network_type}') default_network_mode_name = self.network_mode_names[self.Default_Network_Type] default_profile = self.Default_Profile_name print(f'----------------------------------------默认网络模式为:{default_network_mode_name}') sf.quick_internet_test() print(f'----------------------------------------默认Profile为:{default_profile}') for network_type in self.preferred_network_type: if network_type != self.Default_Network_Type: post_data = {"method":"set", "params":{ "dial_setting":{ "profile_id":"8", "profile_name":"China Unicom" }, "failover_timeout":"100", "network_mode":network_type, "data_roaming":False } } network_mode_name = self.network_mode_names[network_type] print(f'----------------------------------------正在切换为{network_mode_name}模式') resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) time.sleep(5) print(f'----------------------------------------切换成功,正在检查在{network_mode_name}模式下的网络可达性') sf.quick_internet_test() #完成遍历后将网络模式切换回原本模式 print(f'----------------------------------------BasicTest_NetworkSwitch完成!正在将网络模式切换为默认') post_data = {"method": "set", "params": { "dial_setting": { "profile_id": "8", "profile_name": self.Default_Profile_name }, "failover_timeout": "100", "network_mode": self.Default_Network_Type, "data_roaming": False } } self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) print('\n\n\n') def BasicTest_NetworkSearch(self): self.start_search_time = time.time() # 先开始搜索网络,再持续地检测搜索是否完成 post_data = {"method":"start"} try: resp = self._post_model_form_data(model_name='network_mobile', form_name='network_search', data=post_data) if resp.get('error_code') != '0': print("----------------------------------------网络搜索失败") return False except Exception as e: print("----------------------------------------网络搜索失败 % s" % e) #method修改为get,每秒一次持续检测是否搜索成功 max_wait_time = 30 # 最大等待60秒 poll_interval = 1 # 每秒检测一次 search_success = False post_data = {"method": "get"} while not search_success and time.time() - self.start_search_time < max_wait_time: resp = self._post_model_form_data(model_name='network_mobile', form_name='network_search', data=post_data) self.search_response = rp.parse_network_search_response(resp) if self.search_response == None: time.sleep(poll_interval) else: search_success = True self.end_search_time = time.time() if not search_success: self.end_search_time = time.time() print('----------------------------------------搜索网络超时,timeout=30s') search_time = self.end_search_time - self.start_search_time print(f'----------------------------------------搜索网络花费时间为{search_time}') search_result = self.search_response['运营商列表-operator_list'] print(f'----------------------------------------搜索到的运营商列表如下:') for operator_info in search_result: operator = operator_info.get('alpha_short') print(f'----------------------------------------{operator}') print('\n\n\n') def BasicTest_BandSelect(self): self.start_search_time = time.time() post_data = {"method":"start"} #与搜索网络逻辑类似,先开始搜索Band,再持续检测搜索是否成功 try: resp = self._post_model_form_data(model_name='network_mobile', form_name='band_search', data=post_data) if resp.get('error_code') != '0': print("----------------------------------------Band搜索失败") return False except Exception as e: print("----------------------------------------Band搜索失败 % s" % e) #method修改为get,每秒一次持续检测是否搜索成功 max_wait_time = 30 # 最大等待60秒 poll_interval = 1 # 每秒检测一次 search_success = False post_data = {"method": "get"} while not search_success and time.time() - self.start_search_time < max_wait_time: resp = self._post_model_form_data(model_name='network_mobile', form_name='band_search', data=post_data) self.search_response = rp.parse_band_search_response(resp) if self.search_response == None: time.sleep(poll_interval) else: search_success = True self.end_search_time = time.time() if not search_success: self.end_search_time = time.time() print('----------------------------------------搜索网络超时,timeout=30s') search_time = self.end_search_time - self.start_search_time print(f'----------------------------------------搜索网络花费时间为{search_time}') print(f'----------------------------------------搜索到的Band列表如下:') isp = self.search_response['运营商-isp'] search_result = self.search_response['Band列表-searched_list'] for band_info in search_result: belong_to_isp = band_info.get('belong_to_isp') band = band_info.get('band') if belong_to_isp: print(f'----------------------------------------Band:{band},属于运营商{isp}') else: print(f'----------------------------------------Band:{band},不属于任何运营商') #搜索Band成功后,遍历每一个Band检查网络连通性 for band_info in search_result: belong_to_isp = band_info.get('belong_to_isp') band = band_info.get('band') if belong_to_isp: print(f'----------------------------------------正在选择Band: {band},属于运营商{isp},检测网络连通信中') post_data = {"method":"set","params":{"auto":False,"selected_list":[{"band":band,"belong_to_isp":True}]}} self._post_model_form_data(model_name='network_mobile', form_name='band_search', data=post_data) time.sleep(60) sf.quick_internet_test() else: print(f'----------------------------------------正在选择Band: {band},不属于任何运营商,检测网络连通信中') post_data = {"method":"set","params":{"auto":False,"selected_list":[{"band":band,"belong_to_isp":False}]}} self._post_model_form_data(model_name='network_mobile', form_name='band_search', data=post_data) time.sleep(60) sf.quick_internet_test() #遍历完成后将Band模式切换回Auto,检查是否支持连接到2CA网络 print(f'----------------------------------------遍历Band完成!!!正在将Band模式切换回Auto,检查是否支持连接到2CA网络') post_data = {"method":"set","params":{"auto":True}} self._post_model_form_data(model_name='network_mobile', form_name='band_search', data=post_data) time.sleep(60) post_data = {"method": "get"} resp = self._post_model_form_data(model_name='network_mobile', form_name='cellular_info', data=post_data) systemstatus_ltewan = rp.parse_systemstatus_ltewan(resp) print(f'----------------------------------------LTE WAN口信息如下\n{systemstatus_ltewan}') auto_band_list = systemstatus_ltewan.get('频段-band') band_num = len(auto_band_list) if band_num == 1: print(f'----------------------------------------Band数量为1,当前网络环境不支持2CA网络') elif band_num > 1: print(f'----------------------------------------Band数量 > 1,当前网络环境支持2CA网络') def IPV6andIPv4_IPV4andIPV6(self): post_data = {"method":"get"} resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) default_profile = rp.parse_lte_status(resp) preferred_network_type = default_profile['可用网络模式列表-available_network_modes'] Default_Network_Type = preferred_network_type[0] Default_Profile_name = default_profile['配置文件名称-profile_name'] print(f'----------------------------------------默认网络模式为:{self.network_mode_names[Default_Network_Type]}') print(f'----------------------------------------默认Profile为:{Default_Profile_name}') # 新建profile1,PDP type选择IPV4&IPV6,其他配置与默认profile保持一致才能保证拨号成功,新建完成后会自动将当前profile切换为新建profile;并且新建profile1成功后,需要记录下profile1的id,方便之后进行profile切换 post_data = {"method":"add", "params":{ "profile_name":"profile1", "pdp_type":"dual", "apn_type":default_profile['APN类型-apn_type'], "apn":default_profile['APN-apn'], "username":"", "password":"", "authentication_type":default_profile['认证类型-authentication_type'] } } new_profile1_resp = self._post_model_form_data(model_name='network_mobile', form_name='isp_profile_list', data=post_data) time.sleep(3) self.profile1_id = rp.parse_profile_id(new_profile1_resp) # # 开启DUT LAN侧的IPv6,便于其给PC分配IPv6地址来测试IPv6可用性。 post_data = {"method":"set","params":{"index":0,"old":{"name":"LAN","vlanid":"1","proto":"slaac","slaac_type":"delegation","slaac_zone":"WAN7","slaac_prefixid":"0","slaac_dns":"auto","slaac_address":"2408:8469:ff90:70fc:21d:fff:fe00:2284/64","address":"2408:8469:ff90:70fc:21d:fff:fe00:2284/64","ra_status":"on","ra_priority":"medium","ra_valid_lifetime":"86400","ra_prefer_lifetime":"14400"},"new":{"vlanid":"1","proto":"slaac","slaac_type":"delegation","slaac_zone":"WAN7","slaac_addr_prefix":"","slaac_dns":"auto","slaac_address":"2408:8469:ff90:70fc:21d:fff:fe00:2284/64","ra_status":"on","ra_priority":"medium","ra_valid_lifetime":"86400","ra_prefer_lifetime":"14400"},"key":"key-2"}} self._post_model_form_data(model_name='ipv6', form_name='lan_ipv6', data=post_data) print(f'----------------------------------------正在默认网络模式{self.network_mode_names[Default_Network_Type]}下进行网络测试') # sf.quick_internet_test() # sf.quick_ipv6_test() for network_type in preferred_network_type: if network_type != Default_Network_Type: post_data = {"method":"set", "params":{ "dial_setting":{ "profile_id": self.profile1_id, "profile_name":"profile1" }, "failover_timeout":"100", "network_mode":network_type, "data_roaming":False } } network_mode_name = self.network_mode_names[network_type] print(f'----------------------------------------正在切换为{network_mode_name}模式') resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) time.sleep(20) print(f'----------------------------------------切换成功,正在检查在{network_mode_name}模式下的网络可达性') # sf.quick_internet_test() # sf.quick_ipv6_test() # 遍历网络模式完成,将网络模式切换为默认并将拨号profile切换为初始profile print(f'----------------------------------------正在切换为默认网络模式:{Default_Network_Type}和默认profile:{Default_Profile_name}') post_data = {"method":"set", "params":{ "profile_id":default_profile['配置文件id-profile_id'], "profile_name":default_profile['配置文件名称-profile_name'], "pdp_type":default_profile['PDP类型-pdp_type'], "apn_type":default_profile['APN类型-apn_type'], "apn":default_profile['APN-apn'], "username":"", "password":"", "authentication_type":default_profile['认证类型-authentication_type'], } } self._post_model_form_data(model_name='network_mobile', form_name='isp_profile_list', data=post_data) time.sleep(3) post_data = {"method": "set", "params": { "dial_setting": { "profile_id": default_profile['配置文件id-profile_id'], "profile_name": default_profile['配置文件名称-profile_name'] }, "failover_timeout": "100", "network_mode": Default_Network_Type, "data_roaming": False } } self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) time.sleep(3) def IPV6andIPv4_IPv6Only(self): post_data = {"method": "get"} resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) default_profile = rp.parse_lte_status(resp) preferred_network_type = default_profile['可用网络模式列表-available_network_modes'] Default_Network_Type = preferred_network_type[0] Default_Profile_name = default_profile['配置文件名称-profile_name'] print(f'----------------------------------------默认网络模式为:{self.network_mode_names[Default_Network_Type]}') print(f'----------------------------------------默认Profile为:{Default_Profile_name}') # 新建profile2,PDP type选择IPV6,其他配置与默认profile保持一致才能保证拨号成功,新建完成后会自动将当前profile切换为新建profile;并且新建profile2成功后,需要记录下profile2的id,方便之后进行profile切换 post_data = {"method": "add", "params": { "profile_name": "profile2", "pdp_type": "ipv6", "apn_type": default_profile['APN类型-apn_type'], "apn": default_profile['APN-apn'], "username": "", "password": "", "authentication_type": default_profile['认证类型-authentication_type'] } } new_profile2_resp = self._post_model_form_data(model_name='network_mobile', form_name='isp_profile_list', data=post_data) time.sleep(3) self.profile2_id = rp.parse_profile_id(new_profile2_resp) # 在3.1测试中已经开启DUT LAN侧的IPv6给PC分配IPv6地址来测试IPv6可用性,故此处无需重复操作 # post_data = {"method": "set", "params": {"index": 0, "old": {"name": "LAN", "vlanid": "1", "proto": "slaac", # "slaac_type": "delegation", "slaac_zone": "WAN7", # "slaac_prefixid": "0", "slaac_dns": "auto", # "slaac_address": "2408:8469:ff90:70fc:21d:fff:fe00:2284/64", # "address": "2408:8469:ff90:70fc:21d:fff:fe00:2284/64", # "ra_status": "on", "ra_priority": "medium", # "ra_valid_lifetime": "86400", # "ra_prefer_lifetime": "14400"}, # "new": {"vlanid": "1", "proto": "slaac", "slaac_type": "delegation", # "slaac_zone": "WAN7", "slaac_addr_prefix": "", # "slaac_dns": "auto", # "slaac_address": "2408:8469:ff90:70fc:21d:fff:fe00:2284/64", # "ra_status": "on", "ra_priority": "medium", # "ra_valid_lifetime": "86400", "ra_prefer_lifetime": "14400"}, # "key": "key-2"}} # self._post_model_form_data(model_name='ipv6', form_name='lan_ipv6', data=post_data) print( f'----------------------------------------正在默认网络模式{self.network_mode_names[Default_Network_Type]}下进行网络测试') # sf.quick_internet_test() # sf.quick_ipv6_test() for network_type in preferred_network_type: if network_type != Default_Network_Type: post_data = {"method": "set", "params": { "dial_setting": { "profile_id": self.profile2_id, "profile_name": "profile2" }, "failover_timeout": "100", "network_mode": network_type, "data_roaming": False } } network_mode_name = self.network_mode_names[network_type] print(f'----------------------------------------正在切换为{network_mode_name}模式') resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) time.sleep(20) print( f'----------------------------------------切换成功,正在检查在{network_mode_name}模式下的网络可达性') # sf.quick_internet_test() # sf.quick_ipv6_test() # 遍历网络模式完成,将网络模式切换为默认并将拨号profile切换为初始profile print(f'----------------------------------------正在切换为默认网络模式:{Default_Network_Type}和默认profile:{Default_Profile_name}') post_data = {"method": "set", "params": { "profile_id": default_profile['配置文件id-profile_id'], "profile_name": default_profile['配置文件名称-profile_name'], "pdp_type": default_profile['PDP类型-pdp_type'], "apn_type": default_profile['APN类型-apn_type'], "apn": default_profile['APN-apn'], "username": "", "password": "", "authentication_type": default_profile['认证类型-authentication_type'], } } self._post_model_form_data(model_name='network_mobile', form_name='isp_profile_list', data=post_data) time.sleep(3) post_data = {"method": "set", "params": { "dial_setting": { "profile_id": default_profile['配置文件id-profile_id'], "profile_name": default_profile['配置文件名称-profile_name'] }, "failover_timeout": "100", "network_mode": Default_Network_Type, "data_roaming": False } } self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) time.sleep(3) def IPV6andIPv4_SwitchProfile(self): post_data = {"method": "get"} resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) default_profile = rp.parse_lte_status(resp) preferred_network_type = default_profile['可用网络模式列表-available_network_modes'] Default_Network_Type = preferred_network_type[0] Default_Profile_name = default_profile['配置文件名称-profile_name'] print(f'----------------------------------------默认网络模式为:{self.network_mode_names[Default_Network_Type]}') print(f'----------------------------------------默认Profile为:{Default_Profile_name}') profile_sequence = [ (default_profile['配置文件名称-profile_name'], default_profile['配置文件id-profile_id']), ('Profile1', self.profile1_id), ('Profile2', self.profile2_id), ('Profile1', self.profile1_id), (default_profile['配置文件名称-profile_name'], default_profile['配置文件id-profile_id']), ('Profile2', self.profile2_id), (default_profile['配置文件名称-profile_name'], default_profile['配置文件id-profile_id']) ] for profile_name , profile_id in profile_sequence: print(f'----------------------------------------profile正在切换为:{profile_name},其id是{profile_id}') post_data = {"method": "set", "params": { "profile_id": profile_id, "profile_name": profile_name, "pdp_type": default_profile['PDP类型-pdp_type'], "apn_type": default_profile['APN类型-apn_type'], "apn": default_profile['APN-apn'], "username": "", "password": "", "authentication_type": default_profile['认证类型-authentication_type'], } } self._post_model_form_data(model_name='network_mobile', form_name='isp_profile_list', data=post_data) time.sleep(3) post_data = {"method": "set", "params": { "dial_setting": { "profile_id": profile_id, "profile_name": profile_name }, "failover_timeout": "100", "network_mode": 'prefer_lte', "data_roaming": False } } self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) time.sleep(3) print(f'----------------------------------------profile切换为:{profile_name}成功!正在检测网络环境') def Performance_4GPerformance(self): post_data = {"method": "get"} resp = self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) default_profile = rp.parse_lte_status(resp) # 先将网络模式设置为仅4G post_data = {"method": "set", "params": { "dial_setting": { "profile_id": default_profile['配置文件id-profile_id'], "profile_name": default_profile['配置文件名称-profile_name'] }, "failover_timeout": "100", "network_mode": 'only_lte', "data_roaming": False } } self._post_model_form_data(model_name='network_mobile', form_name='setting', data=post_data) time.sleep(3) speedtest_test_result = sf.basic_speedtest() self.test_results.append({ 'case_name': 'Performance_4GPerformance', 'result': 'Ref', 'remarks': speedtest_test_result }) def export_results_to_excel(self, filename=None): """导出测试结果到Excel""" if filename is None: filename = f"test_results_{time.time()}.xlsx" exporter = eo.TestResultExporter(filename) exporter.export_from_dut(self) return filename
最新发布
10-24
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值