Pesquisar este blog

sábado, 21 de maio de 2016

Criando Testes com Psutil matando processos (Automação em Python para Desktop)


    O Psutil (Processos e Utilitários do Sistema) é uma biblioteca multi-plataforma para recuperação de informações sobre a execução de processos e utilização do sistema (CPU, memória, discos, rede) em Python. É útil principalmente para a monitorização do sistema, criação de perfis e limitando recursos e gestão de processos em execução do processo. 

  O mesmo implementa muitas funcionalidades oferecidas pelas ferramentas de linha de comando, tais como: ps, top, lsof, netstat, ifconfig, who, df, kill, free, nice, ionice, iostat, iotop, uptime, pidof, tty, taskset, pmap. Atualmente ele suporta Linux, Windows, OSX, Sun Solaris, FreeBSD, OpenBSD e NetBSD, ambas as arquiteturas de 32 bits e de 64 bits, com versões de Python de 2,6 para 3,5 (usuários do Python 2.4 e 2.5 podem usar 2.1.3 versão). 

  Resumindo é um Canivete Suíço para auxiliar nos testes automatizados. Como assim? Você pode monitorar o consumo de memoria/processamento do seu aplicativo em um determinado teste, ou verifica o antes e o depois de um determinado teste, tendo o total de consumo de memoria no sistema operacional, você pode criar um testes de instalação do seu produto e verificar se o aplicativo após a instalação esta em memoria, assim como desinstalação do seu produto verificando se foram removidos da memoria do sistema operacional. 

  Em sistema embarcado já fiz inúmeros testes tendo que pegar a memoria de um determinado teste, por um período de tempo, por exemplo em um teste o Middleware estava travando em uma funcionalidade quando você voltava do Standby. Com o Psutil podemos monitorar esse teste de forma melhor. O Middleware era em linux eu usava o top e o free, em sistemas desktop o Psutil é maravilhoso, podemos verificar monitorar o uso de memoria, processamento, rede e disco.

Vamos aos exemplos práticos, abaixo funções para pegar o pid de um processo passando o nome, matar uma lista de processos via Psutil e via console e também de forma remota, é super prático e rápido. 
 import subprocess  
 import psutil  
 class TaskKill:  
   def __init__(self):  
     pass  
   # funcao que me passa o nome do app e me retorna o pid.  
   def list_pid(self, app):  
     pid = ''  
     if app:  
       for proc in psutil.process_iter():  
         try:  
           pinfo = proc.as_dict(attrs=['pid', 'name'])  
           if pinfo['name'] == app:  
             pid = pinfo['pid']  
         except psutil.NoSuchProcess:  
           print "o processo nao existe mais."  
           return pid  
         else:  
           print(pinfo)  
     else:  
       print "Voce precisa enviar o nome do processo!"  
     return pid  
   # funcao que me passa uma lista de processo por nome e me retorna uma lista de processos.  
   def lista_processos(self, app):  
     proc_kill = []  
     for proc in psutil.process_iter():  
       try:  
         pinfo = proc.as_dict(attrs=['pid', 'name'])  
         if pinfo['name'] == app:  
           proc_kill.append(proc)  
       except psutil.NoSuchProcess:  
         print "O processo nao existe mais."  
         pass  
       else:  
         print(pinfo)  
     return proc_kill  
   # Funcao que forca matar o processo via force no console.  
   def kill_force(self, pid):  
     if pid:  
       p = psutil.Process(pid)  
       app = p.name()  
       for proc in psutil.process_iter():  
         try:  
           pinfo = proc.as_dict(attrs=['pid', 'name'])  
           if pinfo['name'] == app:  
             print "notepad found!"  
             subprocess.check_output('taskkill /PID ' + str(pid) + ' /F', shell=True)  
             return True  
         except Exception, e:  
           print "Erro Desconhecido: ", e  
           pass  
       else:  
         print "Pid nao enviado!"  
     return False  
   def on_terminate(self, proc):  
     print("process {} terminated with exit code {}".format(proc, proc.returncode))  
   # funcao de envia uma lista de processos e mata o processo via psutil.  
   def psutil_kill(self, procs_kill):  
     status = False  
     procs = procs_kill # a list of Process instances  
     for p in procs:  
       try:  
         p.terminate()  
         print "Terminate processo!"  
         status = True  
       except psutil.NoSuchProcess:  
         print "O processo nao existe mais."  
         pass  
     gone, alive = psutil.wait_procs(procs, timeout=10, callback=on_terminate)  
     for p in alive:  
       print ("couldn't terminate process %s" % p)  
       try:  
         p.kill()  
         print "Kill processo!"  
         status = True  
       except psutil.NoSuchProcess:  
         print "O processo nao existe mais."    
     return status  
   # funcao que matar um processo de forma remota na rede, usando o pskill.  
   def kill_force_remote(self, computer, pid, user, password):  
     print "notepad found!"  
     try:  
       subprocess.check_output(  
         'C:\SysinternalsSuite\pskill.exe -t \\' + '\\' + str(computer) + ' -u ' + str(user) + ' -p ' + \  
         str(password) + ' ' + str(pid), shell=True)  
       return True  
     except Exception, e:  
       print "Erro generico: ", e  
     return False  
 if __name__ == '__main__':  
   obj = TaskKill()  
   pid_num = obj.list_pid('notepad++.exe')  
   test = obj.kill_force(pid_num)  
   print "Kill App: " + str(test)  

Resultado:
C:\Python27\python.exe C:/Users/reiload/Dropbox/python_functions/kill_app.py
{'pid': 0, 'name': 'System Idle Process'}
{'pid': 4, 'name': 'System'}
{'pid': 7120, 'name': 'chrome.exe'}
{'pid': 7444, 'name': 'chrome.exe'}
{'pid': 7548, 'name': 'WUDFHost.exe'}
{'pid': 7964, 'name': 'zatray.exe'}
{'pid': 8064, 'name': 'chrome.exe'}
{'pid': 8088, 'name': 'taskhostex.exe'}
{'pid': 8128, 'name': 'GWX.exe'}
{'pid': 9028, 'name': 'python.exe'}
{'pid': 9124, 'name': 'dasHost.exe'}
{'pid': 9272, 'name': 'chrome.exe'}
{'pid': 9368, 'name': 'chrome.exe'}
{'pid': 9396, 'name': 'chrome.exe'}
{'pid': 9556, 'name': 'cmd.exe'}
{'pid': 9820, 'name': 'chrome.exe'}
{'pid': 10084, 'name': 'jucheck.exe'}
{'pid': 10164, 'name': 'cmd.exe'}
{'pid': 10324, 'name': 'audiodg.exe'}
{'pid': 10836, 'name': 'chrome.exe'}
{'pid': 10848, 'name': 'conhost.exe'}
{'pid': 11832, 'name': 'python.exe'}
{'pid': 12316, 'name': 'fsnotifier.exe'}
{'pid': 12320, 'name': 'pycharm.exe'}
{'pid': 12620, 'name': 'conhost.exe'}
{'pid': 12812, 'name': 'python.exe'}
{'pid': 12864, 'name': 'taskeng.exe'}
{'pid': 12932, 'name': 'chrome.exe'}
{'pid': 13080, 'name': 'chrome.exe'}
{'pid': 13188, 'name': 'conhost.exe'}
{'pid': 13544, 'name': 'conhost.exe'}
{'pid': 14564, 'name': 'chrome.exe'}
{'pid': 15032, 'name': 'notepad++.exe'}
notepad found!
Kill App: True

Process finished with exit code 0

    Quem já não precisou matar um processo no braço? Aqui temos um exemplo de forma automatizada e super prático em Python. Na função  kill_force_remote, se você não sabe qual é o PID, passa o nome do processo que vai funcionar mesmo assim. O que pode ocorrer de o script não funcionar é porque você não tem permissão necessária para o mesmo, podemos adicionar o except psutil.AccessDenied, que vai informar que houve acesso negado. Podemos ir um pouco além com o DDT (data driven test), para fazer ele ler vários processos através de um arquivo de json.
   Se você tem um servidor e todo dia tem que matar uma lista de processos na mão, aqui você tem a solução de seus problemas, fazendo isso de forma automatizada, bom espero que gostem e até o próximo Post.

Referências:
[1] http://pythonhosted.org/psutil/
[2] https://pypi.python.org/pypi/psutil
[3] https://technet.microsoft.com/en-us/sysinternals/pskill.aspx 
[4] https://pypi.python.org/pypi/ddt

Um comentário: