├── _config.yml ├── .gitignore ├── ExemploAPI_ServeRest ├── requirements.txt ├── README.md └── Exemplo_API_ServeRest.robot ├── ExemploSikuli ├── img │ ├── close.png │ ├── helloword.png │ ├── notepad.png │ ├── notepad_workspace.png │ └── windows_start_menu.png ├── ExemploExecucaoRobotSikuli.mp4 └── TesteSikuli.robot ├── ExemploAutoIt ├── SEALsScript.zip └── testeAutoIt.robot ├── ExemploLibraryXML ├── TestXML.robot ├── xmlBaseExemplo.xml └── ResourceXML.robot ├── README.md ├── Demos ├── DemoAPI │ ├── BDDpt-br.robot │ ├── TestCasesAPIRequests.robot │ └── Resource.robot └── DemoWeb │ ├── resources │ ├── BDDpt-br.robot │ └── ResourceBDD.robot │ └── testes │ └── TestCasesBDDExemplo.robot ├── ExemploBDD ├── BDDpt-br.robot ├── TestCasesBDDExemplo.robot └── ResourceBDD.robot ├── SuitePalestraGUTS ├── SuiteExemploAPI │ ├── BDDpt-br.robot │ ├── TestCasesAPIRequests.robot │ └── Resource.robot └── SuiteExemploWEB │ ├── TestCasesCadastroQANinja.robot │ └── ResourceCadastroQANinja.robot ├── ExemploPabot ├── TestCaseLoginChrome.robot ├── TestCaseLoginFirefox.robot └── Resource_steps_login.robot ├── ExemploMyCustomLibrary ├── libraries │ └── decode64.py └── TestCaseExemploMyCustomLibrary.robot ├── ExemploSelenium ├── TestCasesKeywordDrivenExemplo.robot └── Resource.robot ├── ExemploFakerLibrary ├── TesteExemploFakerBrasileiro.robot └── TestCaseExemploFakerLibrary.robot ├── ExemploSOAPTesting ├── TestSOAPTesting.robot ├── consultaProcesso_envio.xml ├── MyCustomSudsLibrary │ ├── utils.py │ ├── monkeypatches.py │ ├── factory.py │ ├── soaplogging.py │ ├── proxy.py │ ├── clientmanagement.py │ ├── wsse.py │ ├── MySudsLibrary.py │ └── options.py ├── ResourceSOAPTesting_withXMLinput.robot └── ResourceSOAPTesting.robot ├── QArentenaBlogTest ├── TestsBlog.robot └── ResourceBlog.robot ├── ExemploDateTimeRobot └── Exemplo_DateTime.robot ├── SuiteCadastroQANinja ├── TestCasesCadastroQANinja.robot └── ResourceCadastroQANinja.robot ├── ExemploAPI ├── tests │ └── TestCasesAPIRequests.robot └── resources │ ├── BDDImplementation.robot │ └── Steps.robot ├── ExemploDataDriven ├── TestCasesDataDrivenExemplo.robot ├── Resource.robot └── TestsCasesExemploMaisDeUmTemplate.robot ├── Exemplo Imap Library ├── exemplo_keyword_usando_ImapLibrary.txt └── CustomImapLibrary.py ├── ExemploBrowser └── browser_example.robot ├── language-robot-framework └── grammars │ └── robottxt.cson └── RabbitMQ ├── ResourceRabbitMQ.robot └── RabbitMqCustom.py /_config.yml: -------------------------------------------------------------------------------- 1 | theme: jekyll-theme-tactile -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | #robotframework 2 | *.html 3 | *.log 4 | *output.xml 5 | *.png 6 | *.pyc 7 | *.zip 8 | playwright-log.txt 9 | Results/ -------------------------------------------------------------------------------- /ExemploAPI_ServeRest/requirements.txt: -------------------------------------------------------------------------------- 1 | robotframework==3.2.2 2 | robotframework-faker==5.0.0 3 | robotframework-requests==0.8.0 4 | -------------------------------------------------------------------------------- /ExemploSikuli/img/close.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayribeirofernandes/testesrobotframework/HEAD/ExemploSikuli/img/close.png -------------------------------------------------------------------------------- /ExemploAutoIt/SEALsScript.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayribeirofernandes/testesrobotframework/HEAD/ExemploAutoIt/SEALsScript.zip -------------------------------------------------------------------------------- /ExemploSikuli/img/helloword.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayribeirofernandes/testesrobotframework/HEAD/ExemploSikuli/img/helloword.png -------------------------------------------------------------------------------- /ExemploSikuli/img/notepad.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayribeirofernandes/testesrobotframework/HEAD/ExemploSikuli/img/notepad.png -------------------------------------------------------------------------------- /ExemploSikuli/img/notepad_workspace.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayribeirofernandes/testesrobotframework/HEAD/ExemploSikuli/img/notepad_workspace.png -------------------------------------------------------------------------------- /ExemploSikuli/img/windows_start_menu.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayribeirofernandes/testesrobotframework/HEAD/ExemploSikuli/img/windows_start_menu.png -------------------------------------------------------------------------------- /ExemploSikuli/ExemploExecucaoRobotSikuli.mp4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mayribeirofernandes/testesrobotframework/HEAD/ExemploSikuli/ExemploExecucaoRobotSikuli.mp4 -------------------------------------------------------------------------------- /ExemploLibraryXML/TestXML.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ResourceXML.robot 3 | 4 | *** Test Case *** 5 | Teste de manipulação de XML 6 | Manipular e conferir XML 7 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Bem-vindo Robotizadores 2 | 3 | Neste repositório deixarei os exemplos que citarei no Blog Robotizando Testes. 4 | 5 | Acesse!(https://robotizandotestes.blogspot.com.br) -------------------------------------------------------------------------------- /Demos/DemoAPI/BDDpt-br.robot: -------------------------------------------------------------------------------- 1 | *** Keywords *** 2 | Dado ${keyword} 3 | Run keyword ${keyword} 4 | 5 | Quando ${keyword} 6 | Run keyword ${keyword} 7 | 8 | Então ${keyword} 9 | Run keyword ${keyword} 10 | 11 | E ${keyword} 12 | Run keyword ${keyword} 13 | -------------------------------------------------------------------------------- /ExemploBDD/BDDpt-br.robot: -------------------------------------------------------------------------------- 1 | *** Keywords *** 2 | Dado ${keyword} 3 | Run keyword ${keyword} 4 | 5 | Quando ${keyword} 6 | Run keyword ${keyword} 7 | 8 | Então ${keyword} 9 | Run keyword ${keyword} 10 | 11 | E ${keyword} 12 | Run keyword ${keyword} -------------------------------------------------------------------------------- /Demos/DemoWeb/resources/BDDpt-br.robot: -------------------------------------------------------------------------------- 1 | *** Keywords *** 2 | Dado ${keyword} 3 | Run keyword ${keyword} 4 | 5 | Quando ${keyword} 6 | Run keyword ${keyword} 7 | 8 | Então ${keyword} 9 | Run keyword ${keyword} 10 | 11 | E ${keyword} 12 | Run keyword ${keyword} 13 | -------------------------------------------------------------------------------- /SuitePalestraGUTS/SuiteExemploAPI/BDDpt-br.robot: -------------------------------------------------------------------------------- 1 | *** Keywords *** 2 | Dado ${keyword} 3 | Run keyword ${keyword} 4 | 5 | Quando ${keyword} 6 | Run keyword ${keyword} 7 | 8 | Então ${keyword} 9 | Run keyword ${keyword} 10 | 11 | E ${keyword} 12 | Run keyword ${keyword} -------------------------------------------------------------------------------- /ExemploPabot/TestCaseLoginChrome.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ./Resource_steps_login.robot 3 | Suite Teardown Close browser 4 | 5 | *** Test Cases *** 6 | Cenário: Login com sucesso 7 | Dado que estou na tela de login no Chrome 8 | Quando realizo o login 9 | Então devo visualizar a mensagem "You logged into a secure area!" 10 | -------------------------------------------------------------------------------- /ExemploPabot/TestCaseLoginFirefox.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ./Resource_steps_login.robot 3 | Suite Teardown Close browser 4 | 5 | *** Test Cases *** 6 | Cenário: Login com sucesso 7 | Dado que estou na tela de login no Firefox 8 | Quando realizo o login 9 | Então devo visualizar a mensagem "You logged into a secure area!" 10 | -------------------------------------------------------------------------------- /ExemploMyCustomLibrary/libraries/decode64.py: -------------------------------------------------------------------------------- 1 | import base64 2 | 3 | def decode_64_to_string(stringEncoded): 4 | print("Deconding [%s] to string." % stringEncoded) 5 | 6 | if not stringEncoded.endswith("=="): 7 | stringEncoded = stringEncoded + "==" 8 | 9 | stringDecoded = base64.b64decode(stringEncoded) 10 | 11 | return stringDecoded.decode('UTF-8') 12 | -------------------------------------------------------------------------------- /ExemploSelenium/TestCasesKeywordDrivenExemplo.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource Resource.robot 3 | Suite Teardown Fechar Navegador 4 | 5 | *** Test Case *** 6 | Validar acesso ao blog robotizandotestes 7 | Acessar blog robotizandotestes 8 | 9 | Validar pesquisa de postagens 10 | Pesquisar a postagem "season premiere" 11 | Clicar no post "Season Premiere: Introdução ao Robot Framework" encontrado -------------------------------------------------------------------------------- /ExemploFakerLibrary/TesteExemploFakerBrasileiro.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Faker com dados brasileiros 3 | Library FakerLibrary locale=pt_BR 4 | 5 | *** Test Cases *** 6 | Teste dados fakes BRASILEIROS 7 | ${CPF} FakerLibrary.cpf 8 | ${NOME} FakerLibrary.name 9 | ${CIDADE} FakerLibrary.city 10 | ${CEP} FakerLibrary.postcode 11 | ${ESTADO} FakerLibrary.state 12 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/TestSOAPTesting.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ResourceSOAPTesting.robot 3 | Resource ResourceSOAPTesting_withXMLinput.robot 4 | 5 | *** Test Case *** 6 | Teste SOAP preenchendo campo a campo da requisição 7 | Enviar requisição SOAP preenchendo campo a campo da requisição 8 | 9 | Teste SOAP enviando um arquivo XML na requisição 10 | Enviar requisição SOAP enviando arquivo XML de input 11 | -------------------------------------------------------------------------------- /ExemploAPI_ServeRest/README.md: -------------------------------------------------------------------------------- 1 | ## Testes de API com Robot Framework utilizando a nova versão da RequestsLibrary [0.8.0] e a API de estudos ServeRest 2 | 3 | As *keywords* tradicionais de *Request* estão sendo substituídas, leia sobre isso na documentação da [RequestsLibrary](https://marketsquare.github.io/robotframework-requests/doc/RequestsLibrary.html) 4 | 5 | Para conhecer a API pública de estudos **ServeRest** que utilizei para os testes [clique aqui](https://serverest.dev/). 6 | -------------------------------------------------------------------------------- /ExemploPabot/Resource_steps_login.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SeleniumLibrary 3 | 4 | *** Variables *** 5 | ${url} https://the-internet.herokuapp.com/login 6 | 7 | *** Keywords *** 8 | Dado que estou na tela de login no ${browser} 9 | open browser ${url} ${browser} 10 | 11 | Quando realizo o login 12 | input text id=username tomsmith 13 | input text id=password SuperSecretPassword! 14 | click button Login 15 | 16 | Então devo visualizar a mensagem "${mensagem}" 17 | element text should be id=flash You logged into a secure area!\n× 18 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/consultaProcesso_envio.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | PGMBH 6 | 12345678 7 | 50224418220178130024 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /QArentenaBlogTest/TestsBlog.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ResourceBlog.robot 3 | Test Setup Acessar página inicial do blog 4 | Test Teardown Fechar Navegador 5 | 6 | 7 | *** Test Cases *** 8 | Caso de Teste 01: Fazer pesquisa de um post 9 | Pesquisar por um post com "Season Premiere: Introdução ao Robot Framework" 10 | Conferir mensagem de pesquisa por "Season Premiere: Introdução ao Robot Framework" 11 | 12 | Caso de Teste 02: Ler um post 13 | Acessar o post "Season Premiere: Introdução ao Robot Framework" 14 | Conferir se a imagem do robô aparece 15 | Conferir se o texto "nesse post vou apresentar-lhes o astro deste blog" aparece 16 | -------------------------------------------------------------------------------- /ExemploLibraryXML/xmlBaseExemplo.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | ID_ANTES 6 | 12345678 7 | 19000101000000 8 | false 9 | true 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /SuitePalestraGUTS/SuiteExemploWEB/TestCasesCadastroQANinja.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ResourceCadastroQANinja.robot 3 | Test Teardown Close Browser 4 | 5 | *** Test Cases *** 6 | Validar Cadastro de Usuário: Email Válido 7 | Acessar Página Principal 8 | Clicar em Cadastro 9 | Inserir Nome Completo 10 | Inserir Email Válido 11 | Inserir Senha 12 | Submeter Cadastro 13 | Conferir Mensagem de Boas Vindas 14 | 15 | Validar Cadastro de Usuário: Email Inválido 16 | Acessar Página Principal 17 | Clicar em Cadastro 18 | Inserir Nome Completo 19 | Inserir Email Inválido 20 | Inserir Senha 21 | Submeter Cadastro 22 | Conferir Mensagem de Alerta de Email Inválido -------------------------------------------------------------------------------- /ExemploBDD/TestCasesBDDExemplo.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ResourceBDD.robot 3 | Resource BDDpt-br.robot 4 | Suite Teardown Fechar Navegador 5 | 6 | *** Test Cases *** 7 | Cenário 01: Pesquisar postagem Season Premiere 8 | Dado que esteja na tela HOME do blog robotizando testes 9 | Quando pesquisar pela palavra "introdução" 10 | Então a postagem "Season Premiere: Introdução ao Robot Framework" deve ser listada no resultado da pesquisa 11 | 12 | Cenário 02: Ler postagem Season Premiere 13 | Dado que esteja na tela de resultado da pesquisa pela postagem "Season Premiere: Introdução ao Robot Framework" 14 | Quando clicar no link da postagem 15 | Então a tela da postagem "Season Premiere: Introdução ao Robot Framework" deve ser mostrada -------------------------------------------------------------------------------- /Demos/DemoWeb/testes/TestCasesBDDExemplo.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ../resources/ResourceBDD.robot 3 | Resource ../resources/BDDpt-br.robot 4 | Suite Teardown Fechar Navegador 5 | 6 | *** Test Cases *** 7 | Cenário 01: Pesquisar postagem Season Premiere 8 | Dado que esteja na tela HOME do blog robotizando testes 9 | Quando pesquisar pela palavra "introdução ao robot framework" 10 | Então a postagem "Season Premiere: Introdução ao Robot Framework" deve ser listada no resultado da pesquisa 11 | 12 | Cenário 02: Ler postagem Season Premiere 13 | Dado que esteja na tela de resultado da pesquisa pela postagem "Season Premiere: Introdução ao Robot Framework" 14 | Quando clicar no link da postagem 15 | Então a tela da postagem "Season Premiere: Introdução ao Robot Framework" deve ser mostrada 16 | -------------------------------------------------------------------------------- /ExemploDateTimeRobot/Exemplo_DateTime.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library DateTime 3 | 4 | *** Variable *** 5 | ${DATA} 2018-01-16 6 | 7 | *** Test Cases *** 8 | Teste Operações com Datas 9 | ####Pegando a data de hoje e convertendo para formato yyyy-mm-dd 10 | ${TODAY} Get Current Date result_format=%Y-%m-%d 11 | ${DATA} Convert Date ${DATA} result_format=%Y-%m-%d 12 | 13 | ####Fazendo o cálculo 14 | ${RESULT} Subtract Date From Date ${TODAY} ${DATA} 15 | ${MONTHS} Evaluate ${RESULT}/60/60/24/30 16 | 17 | ####Formatando para ficar no formato dd-mm-yyyy 18 | ${DATA} Convert Date ${DATA} result_format=%d-%m-%Y 19 | ${TODAY} Convert Date ${TODAY} result_format=%d-%m-%Y 20 | Log Entre ${TODAY} e ${DATA} existem ${MONTHS} meses. 21 | -------------------------------------------------------------------------------- /SuiteCadastroQANinja/TestCasesCadastroQANinja.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource ResourceCadastroQANinja.robot 3 | Test Teardown Close Browser 4 | 5 | *** Test Cases *** 6 | Validar Acesso ao Site QA Ninja 7 | Acessar Página Principal 8 | 9 | Validar Acesso à Página de Cadastro 10 | Acessar Página Principal 11 | Clicar em Cadastro 12 | 13 | Validar Cadastro de Usuário: Email Válido 14 | Acessar Página Principal 15 | Clicar em Cadastro 16 | Inserir Nome Completo 17 | Inserir Email Válido 18 | Inserir Senha 19 | Submeter Cadastro 20 | Conferir Mensagem de Boas Vindas 21 | 22 | Validar Cadastro de Usuário: Email Inválido 23 | Acessar Página Principal 24 | Clicar em Cadastro 25 | Inserir Nome Completo 26 | Inserir Email Inválido 27 | Inserir Senha 28 | Submeter Cadastro 29 | Conferir Mensagem de Alerta de Email Inválido -------------------------------------------------------------------------------- /ExemploAPI/tests/TestCasesAPIRequests.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Suíte de Exemplo de testes API com o Robot Framework 3 | Resource ../resources/BDDImplementation.robot 4 | 5 | *** Test Case *** 6 | Cenário 01: Consulta de endereço existente 7 | [Tags] jenkins 8 | Dado que esteja conectado no webservice de consultas de CEP 9 | Quando o usuário consultar o CEP "88056-000" 10 | Então deve ser mostrado o endereço "Avenida Luiz Boiteux Piazza" 11 | E deve ser mostrado o bairro "Cachoeira do Bom Jesus" 12 | E deve ser mostrada a cidade "Florianópolis" 13 | E deve ser mostrada a UF "SC" 14 | E deve ser mostrado o CEP "88056000" 15 | 16 | Cenário 02: Consulta de endereço inexistente 17 | Dado que esteja conectado no webservice de consultas de CEP 18 | Quando o usuário consultar o CEP "99999-999" 19 | Então a mensagem "CEP INVÁLIDO" deve ser retornada 20 | -------------------------------------------------------------------------------- /ExemploMyCustomLibrary/TestCaseExemploMyCustomLibrary.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Exemplo de uso de uma Library personalizada e criada por mim em Python 3 | ... Essa library irá decodificar uma string em base64 para UTF-8 4 | Library ./libraries/decode64.py 5 | 6 | *** Test Cases *** 7 | Teste da minha custom library 8 | Decodificar o texto "TWluaGEgZnJhc2UgZGUgdGVzdGUh" 9 | Conferir se o texto decodificado é "Minha frase de teste!" 10 | 11 | *** Keywords *** 12 | Decodificar o texto "${TEXTO_CODIFICADO_BASE64}" 13 | ${TEXTO_DECODIFICADO} decode 64 to string ${TEXTO_CODIFICADO_BASE64} 14 | Set Test Variable ${TEXTO_DECODIFICADO} 15 | Log Frase codificada: ${TEXTO_CODIFICADO_BASE64} -- Frase decodificada: ${TEXTO_DECODIFICADO} 16 | 17 | Conferir se o texto decodificado é "${FRASE_ESPERADA}" 18 | Should Be Equal ${TEXTO_DECODIFICADO} ${FRASE_ESPERADA} 19 | -------------------------------------------------------------------------------- /SuitePalestraGUTS/SuiteExemploAPI/TestCasesAPIRequests.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Suíte de Exemplo de testes API com o Robot Framework 3 | Resource BDDpt-br.robot 4 | Resource Resource.robot 5 | 6 | *** Test Case *** 7 | Cenário 01: Consulta de endereço existente 8 | Dado que esteja conectado no webservice de consultas de CEP 9 | Quando o usuário consultar o CEP "88056-000" 10 | Então deve ser mostrado o endereço "Avenida Luiz Boiteux Piazza" 11 | E deve ser mostrado o bairro "Cachoeira do Bom Jesus" 12 | E deve ser mostrada a cidade "Florianópolis" 13 | E deve ser mostrada a UF "SC" 14 | E deve ser mostrado o CEP "88056000" 15 | 16 | Cenário 02: Consulta de endereço inexistente 17 | Dado que esteja conectado no webservice de consultas de CEP 18 | Quando o usuário consultar o CEP "99999-999" 19 | Então nenhum dado deve ser mostrado para o CEP "99999999" -------------------------------------------------------------------------------- /ExemploDataDriven/TestCasesDataDrivenExemplo.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource Resource.robot 3 | Suite Setup Acessar blog robotizandotestes 4 | Suite Teardown Fechar Navegador 5 | Test Template Validar pesquisa de postagens 6 | 7 | *** Test Case *** Busca Título do Post 8 | 9 | Pesquisar Post Premiere introdução Season Premiere: Introdução ao Robot Framework 10 | Pesquisar Post Editores Ep.01 visual code Season Editores - Ep. 02: Visual Studio Code 11 | Pesquisar Post Tutoriais Ep.01 windows Season Tutoriais - Ep. 01: Instalando o Robot Framework (Windows) 12 | 13 | *** Keyword *** 14 | Validar pesquisa de postagens 15 | [Arguments] ${BUSCA} ${TITULO_POSTAGEM} 16 | Pesquisar a postagem pela palavra "${BUSCA}" 17 | Verificar resultado da pesquisa ${TITULO_POSTAGEM} 18 | Clicar no post encontrado 19 | Verificar tela da postagem ${TITULO_POSTAGEM} -------------------------------------------------------------------------------- /ExemploSikuli/TesteSikuli.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Sikuli Library Demo 3 | Test Setup Carrega diretório de imagens 4 | Test Teardown Stop Remote Server 5 | Library SikuliLibrary 6 | 7 | *** Variables *** 8 | #As imagens da pasta img devem estar de acordo com a interface do seu PC!!!! Tire os prints necessários! 9 | ${IMAGE_DIR} ${CURDIR}\\img 10 | 11 | *** Test Cases *** 12 | Windows Notepad Hello World 13 | Abre o menu inicial do windows 14 | Abre o notepad++ 15 | Digita "Hello Word" 16 | Fecha o notepad++ 17 | 18 | *** Keywords *** 19 | Carrega diretório de imagens 20 | Add Image Path ${IMAGE_DIR} 21 | 22 | Abre o menu inicial do windows 23 | Click windows_start_menu.png 24 | 25 | Abre o notepad++ 26 | Click notepad.png 27 | 28 | Digita "${TEXTO}" 29 | Input Text notepad_workspace.png ${TEXTO} 30 | Screen Should Contain helloword.png 31 | 32 | Fecha o notepad++ 33 | Click close.png -------------------------------------------------------------------------------- /ExemploAPI/resources/BDDImplementation.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource Steps.robot 3 | 4 | *** Keywords *** 5 | #### DADO 6 | Dado que esteja conectado no webservice de consultas de CEP 7 | Conecta ao WebService 8 | 9 | #### QUANDO 10 | Quando o usuário consultar o CEP "${CEP_CONSULTADO}" 11 | Realiza requisição do CEP ${CEP_CONSULTADO} 12 | 13 | #### ENTÃO 14 | Então deve ser mostrado o endereço "${ENDERECO}" 15 | Confere o status code 200 16 | Confere endereço do CEP ${ENDERECO} 17 | 18 | E deve ser mostrado o bairro "${BAIRRO}" 19 | Confere bairro do CEP ${BAIRRO} 20 | 21 | E deve ser mostrada a cidade "${CIDADE}" 22 | Confere cidade do CEP ${CIDADE} 23 | 24 | E deve ser mostrada a UF "${UF}" 25 | Confere UF do CEP ${UF} 26 | 27 | E deve ser mostrado o CEP "${CEP}" 28 | Confere CEP ${CEP} 29 | 30 | Então a mensagem "${ERROR_MSG}" deve ser retornada 31 | Confere o status code 200 32 | Confere Mensagem de Erro ${ERROR_MSG} 33 | -------------------------------------------------------------------------------- /Exemplo Imap Library/exemplo_keyword_usando_ImapLibrary.txt: -------------------------------------------------------------------------------- 1 | ----> Fiz uns ajustes no código fonte da library, então usei ela customizada no projeto: 2 | 3 | *** Settings *** 4 | Library CustomImapLibrary.py 5 | 6 | ----> Meu código que funcionava (é um código de 2 anos atrás tá): 7 | 8 | Confere envio de e-mail de alerta de saldo 9 | Open Mailbox host=${IMAP.host} port=${IMAP.port} user=${IMAP.user} password=${IMAP.password} 10 | ${EMAIL_INDEX} Wait For Email sender=blablablabla@gmail.com status=UNSEEN timeout=30 11 | ${BODY} Get Email Body ${EMAIL_INDEX} 12 | Delete Email ${EMAIL_INDEX} 13 | ${BODY} Decode Email Body ${BODY} 14 | Should Contain ${BODY} Cliente: Cliente Teste - Consultas Utilizadas: 1 15 | Close Mailbox 16 | 17 | 18 | ---> tinha a keyword de limpar a caixa no setup do teste: 19 | 20 | Limpar Email 21 | Open Mailbox host=${IMAP.host} port=${IMAP.port} user=${IMAP.user} password=${IMAP.password} 22 | Delete All Emails 23 | Close Mailbox -------------------------------------------------------------------------------- /ExemploAutoIt/testeAutoIt.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library AutoItLibrary 3 | 4 | *** Test Cases *** 5 | Joaninha 6 | Abrir Joaninha 7 | Digitar Defeito 8 | 9 | *** Keywords *** 10 | Abrir Joaninha 11 | # O diretório desse executavel, configurei nas variáveis de ambiente do windows 12 | Run SEALsScript.exe 13 | Win Wait WindowTitle=SEAL´s Scripts 14 | 15 | Digitar Defeito 16 | Control Focus strTitle=SEAL´s Scripts strText=${EMPTY} strControl=TMemo4 17 | Send Meu texto para o campo Descrição do Defeito 18 | Control Focus strTitle=SEAL´s Scripts strText=${EMPTY} strControl=TEdit1 19 | Send Meu texto para o campo Aplicativo 20 | Control Focus strTitle=SEAL´s Scripts strText=${EMPTY} strControl=TMemo2 21 | Send Meu texto para o campo Procedimento do Teste 22 | Control Focus strTitle=SEAL´s Scripts strText=${EMPTY} strControl=TMemo1 23 | Send Meu texto para o campo Evidências 24 | Control Click strTitle=SEAL´s Scripts strText=Copiar strControl=TBitBtn2 25 | -------------------------------------------------------------------------------- /ExemploBrowser/browser_example.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library Browser 3 | 4 | 5 | *** Test Cases *** 6 | Exemplo com a library Browser 7 | Abrindo uma tab no navegador no site http://www.google.com.br 8 | Fazer pesquisa com a frase robot framework 9 | Verificar se aparece o header do Robot Framework 10 | 11 | 12 | *** Keywords *** 13 | Abrindo uma tab no navegador no site 14 | [Arguments] ${url} 15 | # Por default o browser será headless, aqui optamos por ver o browser 16 | New Browser headless=False 17 | 18 | # Quero um contexto de teste que GRAVE as execuções 19 | New Context recordVideo={'dir': '${OUTPUT_DIR}/video'} 20 | 21 | # Abro uma ABA no navegador com a URL desejada 22 | New Page url=${url} 23 | 24 | Fazer pesquisa com a frase 25 | [Arguments] ${frase_pesquisa} 26 | Fill Text css=input[name=q] ${frase_pesquisa} 27 | Click :nth-match(:text("Pesquisa Google"), 2) 28 | 29 | Verificar se aparece o header do Robot Framework 30 | # As asserções são feitas com Getters, onde passamos o locator + 31 | # a condição + o valor esperado tudo na mesma linha, nessa ordem 32 | Get Text h2 > span == Robot Framework 33 | -------------------------------------------------------------------------------- /Demos/DemoAPI/TestCasesAPIRequests.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Suíte de Exemplo de testes API com o Robot Framework 3 | Resource BDDpt-br.robot 4 | Resource Resource.robot 5 | 6 | *** Test Case *** 7 | Cenário 01: Consulta de endereço existente 8 | Dado que esteja conectado no webservice de consultas de CEP 9 | Quando o usuário consultar o CEP "88056-000" 10 | Então deve ser mostrado o endereço "Avenida Luiz Boiteux Piazza" 11 | E deve ser mostrado o bairro "Cachoeira do Bom Jesus" 12 | E deve ser mostrada a cidade "Florianópolis" 13 | E deve ser mostrada a UF "SC" 14 | E deve ser mostrado o CEP "88056000" 15 | 16 | ##Cenário 02 Depreciado em 12/04/2019 devido atualização na API 17 | # Cenário 02: Consulta de endereço inexistente 18 | # Dado que esteja conectado no webservice de consultas de CEP 19 | # Quando o usuário consultar o CEP "99999-999" 20 | # Então nenhum dado deve ser mostrado para o CEP "99999999" 21 | 22 | Cenário 03: Consulta de endereço inexistente 23 | Dado que esteja conectado no webservice de consultas de CEP 24 | Quando o usuário consultar o CEP "99999-999" 25 | Então a mensagem de erro "CEP INVÁLIDO" deve ser retornada 26 | -------------------------------------------------------------------------------- /ExemploSelenium/Resource.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SeleniumLibrary 3 | 4 | *** Variable *** 5 | ${BROWSER} firefox 6 | ${URL} https://robotizandotestes.blogspot.com.br/ 7 | ${CABEÇALHO} Header1 8 | ${BOTAO_LUPA} css=.search-expand.touch-icon-button 9 | ${CAMPO_PESQUISAR} css=.search-input>input 10 | ${BOTAO_PESQUISAR} css=.search-action.flat-button 11 | ${LINK_POST} xpath=.//*[@id='Blog1']/div[1]/article/div/div/h3/a 12 | ${TITULO_POST} xpath=.//*[@id='Blog1']/div/article/div[1]/div/h3 13 | 14 | *** Keywords *** 15 | Acessar blog robotizandotestes 16 | Open Browser ${URL} ${BROWSER} 17 | Wait Until Element Is Visible ${CABEÇALHO} 18 | Title Should Be Robotizando Testes 19 | 20 | Pesquisar a postagem "${PESQUISA}" 21 | Click Element ${BOTAO_LUPA} 22 | Input Text ${CAMPO_PESQUISAR} ${PESQUISA} 23 | Click Element ${BOTAO_PESQUISAR} 24 | Wait Until Element Is Visible ${LINK_POST} 25 | 26 | Clicar no post "${TITULO_POST_DESC}" encontrado 27 | Click Element ${LINK_POST} 28 | Wait Until Element Is Visible ${TITULO_POST} 29 | Title Should Be ${TITULO_POST_DESC} 30 | 31 | Fechar Navegador 32 | Close Browser 33 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/utils.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from robot import utils 16 | 17 | 18 | # assumed that no WSDL will have a service or port named "1", etc. 19 | def parse_index(value): 20 | try: 21 | return int(value) 22 | except (ValueError, TypeError): 23 | return value 24 | 25 | 26 | def to_bool(item): 27 | if isinstance(item, str): 28 | if utils.eq(item, 'True'): 29 | return True 30 | if utils.eq(item, 'False'): 31 | return False 32 | return bool(item) 33 | 34 | 35 | def format_robot_time(timestr): 36 | secs = utils.timestr_to_secs(timestr) 37 | return utils.secs_to_timestr(secs) 38 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/ResourceSOAPTesting_withXMLinput.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | ### Para rodar esse exemplo foi necessária uma correção na Library SudsLibrary 3 | ### Issue: https://github.com/ombre42/robotframework-sudslibrary/issues/32 4 | ### Por isso uso a minha library customizada MySudsLibrary.py, que já fiz a correção 5 | Library ./MyCustomSudsLibrary/MySudsLibrary.py 6 | Library OperatingSystem 7 | 8 | *** Variables *** 9 | ### Você vai precisar o WSDL do seu webservice/SOAP Client destino 10 | ${WSDL_URL} http://localhost:8077/servico-intercomunicacao-2.2.2/intercomunicacao?wsdl 11 | 12 | *** Keywords *** 13 | Enviar requisição SOAP enviando arquivo XML de input 14 | ### Abra a conexão com o SOAP Cliente destino 15 | MySudsLibrary.Create Soap Client ${WSDL_URL} 16 | 17 | ### Pegue um XML no diretório 18 | ${MESSAGE} Get File consultaProcesso_envio.xml 19 | 20 | ### Transforme ele em um Raw Message para ser enviado na requisição 21 | ${MESSAGE} MySudsLibrary.Create Raw Soap Message ${MESSAGE} 22 | Log Mensagem enviada:\n${MESSAGE} 23 | 24 | ### Faça a requisição SOAP 25 | MySudsLibrary.Call Soap Method consultarProcesso ${MESSAGE} 26 | 27 | ### Pegue o XML recebido 28 | ${RESPOSTA_XML} MySudsLibrary.Get Last Received 29 | Log Mensagem Recebida:\n${RESPOSTA_XML} 30 | -------------------------------------------------------------------------------- /ExemploDataDriven/Resource.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SeleniumLibrary 3 | 4 | *** Variable *** 5 | ${BROWSER} firefox 6 | ${URL} https://robotizandotestes.blogspot.com.br/ 7 | ${CABEÇALHO} Header1 8 | ${BOTAO_LUPA} css=.search-expand.touch-icon-button 9 | ${CAMPO_PESQUISAR} css=.search-input>input 10 | ${BOTAO_PESQUISAR} css=.search-action.flat-button 11 | ${LINK_POST} xpath=.//*[@id='Blog1']/div[1]/article/div/div/h3/a 12 | ${TITULO} xpath=.//*[@id='Blog1']/div/article/div[1]/div/h3 13 | 14 | *** Keywords *** 15 | Acessar blog robotizandotestes 16 | Open Browser ${URL} ${BROWSER} 17 | Wait Until Element Is Visible ${CABEÇALHO} 18 | Title Should Be Robotizando Testes 19 | 20 | Pesquisar a postagem pela palavra "${BUSCA}" 21 | Click Element ${BOTAO_LUPA} 22 | Input Text ${CAMPO_PESQUISAR} ${BUSCA} 23 | Click Element ${BOTAO_PESQUISAR} 24 | Wait Until Element Is Visible ${LINK_POST} 25 | 26 | Verificar resultado da pesquisa 27 | [Arguments] ${TITULO_POSTAGEM} 28 | Page Should Contain ${TITULO_POSTAGEM} 29 | 30 | Clicar no post encontrado 31 | Click Element ${LINK_POST} 32 | 33 | Verificar tela da postagem 34 | [Arguments] ${TITULO_POSTAGEM} 35 | Wait Until Element Is Visible ${TITULO} 36 | Title Should Be ${TITULO_POSTAGEM} 37 | 38 | Fechar Navegador 39 | Close Browser -------------------------------------------------------------------------------- /ExemploSOAPTesting/ResourceSOAPTesting.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | ### Instale a library: pip install robotframework-sudslibrary-aljcalandra 3 | Library SudsLibrary 4 | 5 | *** Variables *** 6 | ### Você vai precisar o WSDL do seu webservice/SOAP Client destino 7 | ${WSDL_URL} http://localhost:8077/servico-intercomunicacao-2.2.2/intercomunicacao?wsdl 8 | 9 | ### Você deverá montar um dicionário com os dados que precisa passar na chamada do método 10 | ### Esse exemplo abaixo são os campos obrigatórios do método 11 | ### Esses campos são os mesmos do arquivo consultaProcesso_envio.xml 12 | &{MSG_ENVIO} idConsultante=PGMBH senhaConsultante=12345678 numeroProcesso=50224418220178130024 13 | 14 | *** Keywords *** 15 | Enviar requisição SOAP preenchendo campo a campo da requisição 16 | ### Abra a conexão com o SOAP Cliente destino 17 | SudsLibrary.Create Soap Client ${WSDL_URL} 18 | 19 | ### Chame o método passando campo a campo da requisição 20 | ### A resposta será armazenada na variável ${RESPOSTA_XML} 21 | SudsLibrary.Call Soap Method consultarProcesso 22 | ... ${MSG_ENVIO.idConsultante} 23 | ... ${MSG_ENVIO.senhaConsultante} 24 | ... ${MSG_ENVIO.numeroProcesso} 25 | 26 | ### Pegue o XML recebido 27 | ${RESPOSTA_XML} SudsLibrary.Get Last Received 28 | Log Mensagem Recebida:\n${RESPOSTA_XML} 29 | -------------------------------------------------------------------------------- /QArentenaBlogTest/ResourceBlog.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SeleniumLibrary 3 | 4 | *** Variables *** 5 | ${URL} https://robotizandotestes.blogspot.com/ 6 | ${BROWSER} chrome 7 | ${BTN_PESQUISA} css=.search-expand.touch-icon-button 8 | ${INPUT_PESQUISA} name=q 9 | ${SUBMIT_PESQUISA} css=.search-action.flat-button 10 | ${LINK_POST} xpath=//a[contains(text(),'Season Premiere: Introdução ao Robot Framework')] 11 | ${IMG_ROBO} xpath=//img[contains(@src,'if_Robot_18_385830_grande')] 12 | 13 | *** Keywords *** 14 | Acessar página inicial do blog 15 | Open Browser ${URL} ${BROWSER} 16 | Title Should Be Robotizando Testes 17 | 18 | Fechar Navegador 19 | Close Browser 20 | 21 | Pesquisar por um post com "${TEXTO_PESQUISA}" 22 | Wait Until Element Is Visible ${BTN_PESQUISA} 23 | Click Button ${BTN_PESQUISA} 24 | Input Text ${INPUT_PESQUISA} ${TEXTO_PESQUISA} 25 | Click Button ${SUBMIT_PESQUISA} 26 | 27 | Conferir mensagem de pesquisa por "${TEXTO_PESQUISA}" 28 | Page Should Contain Mostrando postagens que correspondem à pesquisa por ${TEXTO_PESQUISA} 29 | 30 | Acessar o post "${POST}" 31 | Pesquisar por um post com "${POST}" 32 | Click Element ${LINK_POST} 33 | Wait Until Page Contains O que é Robot Framework? 34 | 35 | Conferir se a imagem do robô aparece 36 | Page Should Contain Image ${IMG_ROBO} 37 | 38 | Conferir se o texto "${TEXTO_DESEJADO}" aparece 39 | Page Should Contain ${TEXTO_DESEJADO} 40 | -------------------------------------------------------------------------------- /Demos/DemoWeb/resources/ResourceBDD.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SeleniumLibrary 3 | 4 | *** Variable *** 5 | ${BROWSER} chrome 6 | ${URL} https://robotizandotestes.blogspot.com.br/ 7 | ${CABEÇALHO} id=Header1 8 | ${BOTAO_LUPA} css=.search-expand.touch-icon-button 9 | ${CAMPO_PESQUISAR} css=.search-input>input 10 | ${BOTAO_PESQUISAR} css=.search-action.flat-button 11 | ${LINK_POST} xpath=.//*[@id='Blog1']/div[1]/article/div/div/h3/a 12 | ${TITULO} xpath=.//*[@id='Blog1']/div/article/div[1]/div/h3 13 | 14 | *** Keywords *** 15 | #### DADO 16 | Que esteja na tela HOME do blog robotizando testes 17 | Open Browser ${URL} ${BROWSER} 18 | Wait Until Element Is Visible ${CABEÇALHO} 19 | Title Should Be Robotizando Testes 20 | 21 | Que esteja na tela de resultado da pesquisa pela postagem "${TITULO_POSTAGEM}" 22 | Page Should Contain ${TITULO_POSTAGEM} 23 | 24 | #### QUANDO 25 | Pesquisar pela palavra "${BUSCA}" 26 | Click Element ${BOTAO_LUPA} 27 | Input Text ${CAMPO_PESQUISAR} ${BUSCA} 28 | Sleep 2s 29 | Click Element ${BOTAO_PESQUISAR} 30 | Wait Until Element Is Visible ${LINK_POST} 31 | 32 | Clicar no link da postagem 33 | Click Element ${LINK_POST} 34 | Sleep 2s 35 | 36 | #### ENTÃO 37 | A postagem "${TITULO_POSTAGEM}" deve ser listada no resultado da pesquisa 38 | Page Should Contain ${TITULO_POSTAGEM} 39 | 40 | A tela da postagem "${TITULO_POSTAGEM}" deve ser mostrada 41 | Wait Until Element Is Visible ${TITULO} 42 | Title Should Be ${TITULO_POSTAGEM} 43 | Sleep 2s 44 | 45 | #### TEARDOWN 46 | Fechar Navegador 47 | Close Browser 48 | -------------------------------------------------------------------------------- /language-robot-framework/grammars/robottxt.cson: -------------------------------------------------------------------------------- 1 | 'comment': '\n\tRobot Framework syntax highlighting for txt format.\t\n\t' 2 | 'fileTypes': [ 3 | 'robot' 4 | ] 5 | 'name': 'Robot Framework' 6 | 'firstLineMatch': '\\*{3} (?i:Settings|Keywords|Variables|Test Cases) \\*{3}' 7 | 'patterns': [ 8 | { 9 | 'match': '(^\\*\\*\\*.*?\\*\\*\\*)|((?<=^\\|)\\s+\\*\\*\\*.*?\\*\\*\\*)' 10 | 'name': 'string.robot.header' 11 | } 12 | { 13 | 'include': '#tag' 14 | } 15 | { 16 | 'include': '#variables' 17 | } 18 | { 19 | 'include': '#comment' 20 | } 21 | { 22 | 'begin': '^(?![ \\t\\n\\*\\|])' 23 | 'contentName': 'keyword.control.robot' 24 | 'end': '\\s{2,}|\\t|$' 25 | 'patterns': [ 26 | { 27 | 'include': '#variables' 28 | } 29 | ] 30 | } 31 | { 32 | 'match': '(?:^[\\s\\t]+)(Dado|Quando|Então|E |Mas)' 33 | 'captures': 34 | '1': 35 | 'name': 'keyword.control.robot' 36 | } 37 | ] 38 | 'repository': 39 | 'variables': 40 | 'begin': '([\\$@&]{)' 41 | 'beginCaptures': 42 | '0': 43 | 'name': 'punctuation.section.embedded.begin.robot' 44 | '1': 45 | 'name': 'text.robot' 46 | 'end': '(})' 47 | 'contentName': 'variable.control.robot' 48 | 'endCaptures': 49 | '0': 50 | 'name': 'punctuation.section.embedded.end.robot' 51 | '1': 52 | 'name': 'text.robot' 53 | 'comment': 54 | 'match': '(?:^[\\s\\t]*)(#.*)$' 55 | 'captures': 56 | '1': 57 | 'name': 'comment.line.robot' 58 | 'tag': 59 | 'match': '^[\\s\\t]*(\\[.+\\])' 60 | 'captures': 61 | '0': 62 | 'name': 'entity.tag.name.robot' 63 | '1': 64 | 'name': 'text.robot' 65 | 'scopeName': 'text.robot' 66 | -------------------------------------------------------------------------------- /ExemploAPI/resources/Steps.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library RequestsLibrary 3 | Library Collections 4 | 5 | *** Variable *** 6 | ${HOST} https://webmaniabr.com/api/1/cep 7 | ${APP_KEY} njMf2EiyQ17g6C3vLUxk1yEsWTforVqf 8 | ${APP_SECRET} EgpTuUcM93IqHY8icgR3cK6Cn4bOlkQwSlfLd6ryMjrhhwMW 9 | 10 | *** Keywords *** 11 | #### STEPS 12 | Conecta ao WebService 13 | Create Session consultaCEP ${HOST} disable_warnings=True 14 | 15 | Realiza requisição do CEP 16 | [Arguments] ${CEP_DESEJADO} 17 | ${RESPOSTA}= Get Request consultaCEP /${CEP_DESEJADO}/?app_key=${APP_KEY}&app_secret=${APP_SECRET} 18 | Log Resposta: ${RESPOSTA.text} 19 | Set Test Variable ${RESPOSTA} 20 | 21 | Confere o status code 22 | [Arguments] ${STATUS_ESPERADO} 23 | Should Be Equal As Strings ${RESPOSTA.status_code} ${STATUS_ESPERADO} 24 | Log Status Code Retornado: ${RESPOSTA.status_code} -- Status Code Esperado: ${STATUS_ESPERADO} 25 | 26 | Confere endereço do CEP 27 | [Arguments] ${ENDERECO} 28 | Dictionary Should Contain Item ${RESPOSTA.json()} endereco ${ENDERECO} 29 | 30 | Confere bairro do CEP 31 | [Arguments] ${BAIRRO} 32 | Dictionary Should Contain Item ${RESPOSTA.json()} bairro ${BAIRRO} 33 | 34 | Confere cidade do CEP 35 | [Arguments] ${CIDADE} 36 | Dictionary Should Contain Item ${RESPOSTA.json()} cidade ${CIDADE} 37 | 38 | Confere UF do CEP 39 | [Arguments] ${UF} 40 | Dictionary Should Contain Item ${RESPOSTA.json()} uf ${UF} 41 | 42 | Confere CEP 43 | [Arguments] ${CEP} 44 | Dictionary Should Contain Item ${RESPOSTA.json()} cep ${CEP} 45 | 46 | Confere Mensagem de Erro 47 | [Arguments] ${ERROR_MSG} 48 | Dictionary Should Contain Item ${RESPOSTA.json()} error ${ERROR_MSG} 49 | -------------------------------------------------------------------------------- /ExemploBDD/ResourceBDD.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SeleniumLibrary 3 | 4 | *** Variable *** 5 | ${BROWSER} firefox 6 | ${URL} https://robotizandotestes.blogspot.com.br/ 7 | ${CABEÇALHO} Header1 8 | ${BOTAO_LUPA} css=.search-expand.touch-icon-button 9 | ${CAMPO_PESQUISAR} css=.search-input>input 10 | ${BOTAO_PESQUISAR} css=.search-action.flat-button 11 | ${LINK_POST} xpath=.//*[@id='Blog1']/div[1]/article/div/div/h3/a 12 | ${TITULO} xpath=.//*[@id='Blog1']/div/article/div[1]/div/h3 13 | 14 | *** Keywords *** 15 | #### DADO 16 | Que esteja na tela HOME do blog robotizando testes 17 | Acessar blog robotizandotestes 18 | 19 | Que esteja na tela de resultado da pesquisa pela postagem "${TITULO_POSTAGEM}" 20 | Verificar resultado da pesquisa ${TITULO_POSTAGEM} 21 | 22 | #### QUANDO 23 | Pesquisar pela palavra "${BUSCA}" 24 | Pesquisar a postagem pela palavra "${BUSCA}" 25 | 26 | Clicar no link da postagem 27 | Clicar no post encontrado 28 | 29 | #### ENTÃO 30 | A postagem "${TITULO_POSTAGEM}" deve ser listada no resultado da pesquisa 31 | Verificar resultado da pesquisa ${TITULO_POSTAGEM} 32 | 33 | A tela da postagem "${TITULO_POSTAGEM}" deve ser mostrada 34 | Verificar tela da postagem ${TITULO_POSTAGEM} 35 | 36 | #### PASSOS 37 | Acessar blog robotizandotestes 38 | Open Browser ${URL} ${BROWSER} 39 | Wait Until Element Is Visible ${CABEÇALHO} 40 | Title Should Be Robotizando Testes 41 | 42 | Pesquisar a postagem pela palavra "${BUSCA}" 43 | Click Element ${BOTAO_LUPA} 44 | Input Text ${CAMPO_PESQUISAR} ${BUSCA} 45 | Click Element ${BOTAO_PESQUISAR} 46 | Wait Until Element Is Visible ${LINK_POST} 47 | 48 | Verificar resultado da pesquisa 49 | [Arguments] ${TITULO_POSTAGEM} 50 | Page Should Contain ${TITULO_POSTAGEM} 51 | 52 | Clicar no post encontrado 53 | Click Element ${LINK_POST} 54 | 55 | Verificar tela da postagem 56 | [Arguments] ${TITULO_POSTAGEM} 57 | Wait Until Element Is Visible ${TITULO} 58 | Title Should Be ${TITULO_POSTAGEM} 59 | 60 | Fechar Navegador 61 | Close Browser -------------------------------------------------------------------------------- /ExemploDataDriven/TestsCasesExemploMaisDeUmTemplate.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Resource Resource.robot 3 | Suite Setup Acessar blog robotizandotestes 4 | Suite Teardown Fechar Navegador 5 | Test Template Validar pesquisa de postagens 6 | 7 | *** Test Case *** 8 | Pesquisar Post Premiere no template 1 9 | [Template] Validar pesquisa de postagens 1 10 | # Busca Título do Post 11 | introdução Season Running - Ep. 08: Executando seus testes no Docker 12 | 13 | Pesquisar Post Premiere no template 2 14 | [Template] Validar pesquisa de postagens 2 15 | # Busca Título do Post 16 | introdução Season Running - Ep. 08: Executando seus testes no Docker 17 | 18 | Pesquisar Post Editores Ep.01 no template 1 19 | [Template] Validar pesquisa de postagens 1 20 | # Busca Título do Post 21 | visual code Season Editores - Ep. 02: Visual Studio Code - Configurando o VS Code para o Robot Framework 22 | 23 | Pesquisar Post Editores Ep.01 no template 2 24 | [Template] Validar pesquisa de postagens 2 25 | # Busca Título do Post 26 | visual code Season Editores - Ep. 02: Visual Studio Code - Configurando o VS Code para o Robot Framework 27 | 28 | Pesquisar Post Tutoriais Ep.01 no template 1 29 | [Template] Validar pesquisa de postagens 1 30 | # Busca Título do Post 31 | windows Season Mobile com Appium - Ep.01: Instalação Windows 32 | 33 | Pesquisar Post Tutoriais Ep.01 no template 2 34 | [Template] Validar pesquisa de postagens 2 35 | # Busca Título do Post 36 | windows Season Mobile com Appium - Ep.01: Instalação Windows 37 | 38 | *** Keyword *** 39 | Validar pesquisa de postagens 1 40 | [Arguments] ${BUSCA} ${TITULO_POSTAGEM} 41 | Pesquisar a postagem pela palavra "${BUSCA}" 42 | Verificar resultado da pesquisa ${TITULO_POSTAGEM} 43 | Clicar no post encontrado 44 | Verificar tela da postagem ${TITULO_POSTAGEM} 45 | 46 | Validar pesquisa de postagens 2 47 | [Arguments] ${BUSCA} ${TITULO_POSTAGEM} 48 | Pesquisar a postagem pela palavra "${BUSCA}" 49 | Verificar resultado da pesquisa ${TITULO_POSTAGEM} 50 | Clicar no post encontrado 51 | Verificar tela da postagem ${TITULO_POSTAGEM} 52 | -------------------------------------------------------------------------------- /ExemploFakerLibrary/TestCaseExemploFakerLibrary.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Exemplo de uso da Library Faker 3 | Library FakerLibrary 4 | 5 | *** Test Cases *** 6 | Imprime exemplos de utilidades da library FakerLibrary 7 | Exemplos relacionados a pessoa 8 | Exemplos relacionados a datas 9 | Exemplos diversos 10 | 11 | *** Keywords *** 12 | Exemplos relacionados a pessoa 13 | ${NOMEFAKE} FakerLibrary.Name 14 | ${ENDERECOFAKE} FakerLibrary.Address 15 | ${TELEFONEFAKE} FakerLibrary.Phone Number 16 | ${CIDADEFAKE} FakerLibrary.City 17 | ${CODIGOPOSTALFAKE} FakerLibrary.Postalcode 18 | ${TRABALHOFAKE} FakerLibrary.Job 19 | @{PESSOA} Create List Nome Aleatório: ${NOMEFAKE} Endereço Aleatório: ${ENDERECOFAKE} 20 | ... Telefone Aleatório: ${TELEFONEFAKE} Cidade Aleatória: ${CIDADEFAKE} 21 | ... CódigoPostal Aleatório: ${CODIGOPOSTALFAKE} Trabalho: ${TRABALHOFAKE} 22 | Log Many @{PESSOA} 23 | 24 | Exemplos relacionados a datas 25 | ${DATAFAKE} FakerLibrary.Date 26 | ${MESFAKE} FakerLibrary.Month 27 | ${ANOFAKE} FakerLibrary.Year 28 | ${DIADASEMANAFAKE} FakerLibrary.Day Of Week 29 | ${DIADOMESFAKE} FakerLibrary.Day Of Month 30 | @{DATAS} Create List Data Aleatória: ${DATAFAKE} Mês Aleatório: ${MESFAKE} Ano Aleatório: ${ANOFAKE} 31 | ... Dia da Semana Aleatório: ${DIADASEMANAFAKE} Dia do Mês Aleatório: ${DIADOMESFAKE} 32 | Log Many @{DATAS} 33 | 34 | Exemplos diversos 35 | ${EMAILFAKE} FakerLibrary.Email 36 | ${PASSWORDFAKE} FakerLibrary.Password 37 | ${CORFAKE} FakerLibrary.Color Name 38 | ${CARTAODECREDITOFAKE} FakerLibrary.Credit Card Number 39 | ${PALAVRAFAKE} FakerLibrary.Word 40 | @{OUTROS} Create List E-mail Aleatório: ${EMAILFAKE} Senha Aleatória: ${PASSWORDFAKE} 41 | ... Cor Aleatório: ${CORFAKE} Cartão de Crédito Aleatório: ${CARTAODECREDITOFAKE} 42 | ... Palavra Aleatória: ${PALAVRAFAKE} 43 | Log Many @{OUTROS} 44 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/monkeypatches.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import sys 16 | import xml.dom.minidom 17 | from suds.sax.document import Document 18 | 19 | 20 | py_version = sys.version_info[0] + sys.version_info[1] * 0.1 21 | if py_version < 3.3: 22 | class _ElementMonkeyPathes(object): 23 | # from http://ronrothman.com/public/leftbraned/xml-dom-minidom-toprettyxml-and-silly-whitespace/ 24 | 25 | def fixed_writexml(self, writer, indent="", addindent="", newl=""): 26 | writer.write(indent + "<" + self.tagName) 27 | attrs = self._get_attributes() 28 | a_names = list(attrs.keys()) 29 | a_names.sort() 30 | for a_name in a_names: 31 | writer.write(" %s=\"" % a_name) 32 | xml.dom.minidom._write_data(writer, attrs[a_name].value) 33 | writer.write("\"") 34 | if self.childNodes: 35 | if len(self.childNodes) == 1 \ 36 | and self.childNodes[0].nodeType == xml.dom.minidom.Node.TEXT_NODE: 37 | writer.write(">") 38 | self.childNodes[0].writexml(writer, "", "", "") 39 | writer.write("%s" % (self.tagName, newl)) 40 | return 41 | writer.write(">%s" % newl) 42 | for node in self.childNodes: 43 | node.writexml(writer, indent + addindent, addindent, newl) 44 | writer.write("%s%s" % (indent, self.tagName, newl)) 45 | else: 46 | writer.write("/>%s" % newl) 47 | 48 | xml.dom.minidom.Element.writexml = fixed_writexml 49 | 50 | 51 | class _DocumentMonkeyPatches(object): 52 | # fixes AttributeError in debug log event that fails the keyword 53 | 54 | def str(self): 55 | s = [] 56 | s.append(self.DECL) 57 | s.append('\n') 58 | s.append(self.root().str() if self.root() is not None else '') 59 | return ''.join(s) 60 | 61 | Document.str = str 62 | -------------------------------------------------------------------------------- /SuitePalestraGUTS/SuiteExemploAPI/Resource.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library RequestsLibrary 3 | Library Collections 4 | 5 | *** Variable *** 6 | ${HOST} https://webmaniabr.com/api/1/cep 7 | ${APP_KEY} njMf2EiyQ17g6C3vLUxk1yEsWTforVqf 8 | ${APP_SECRET} EgpTuUcM93IqHY8icgR3cK6Cn4bOlkQwSlfLd6ryMjrhhwMW 9 | 10 | *** Keywords *** 11 | #### DADO 12 | Que esteja conectado no webservice de consultas de CEP 13 | Conecta ao WebService 14 | 15 | #### QUANDO 16 | O usuário consultar o CEP "${CEP_CONSULTADO}" 17 | Realiza requisição do CEP ${CEP_CONSULTADO} 18 | 19 | #### ENTÃO 20 | Deve ser mostrado o endereço "${ENDERECO}" 21 | Confere o status code 200 22 | Confere endereço do CEP ${ENDERECO} 23 | 24 | Deve ser mostrado o bairro "${BAIRRO}" 25 | Confere bairro do CEP ${BAIRRO} 26 | 27 | Deve ser mostrada a cidade "${CIDADE}" 28 | Confere cidade do CEP ${CIDADE} 29 | 30 | Deve ser mostrada a UF "${UF}" 31 | Confere UF do CEP ${UF} 32 | 33 | Deve ser mostrado o CEP "${CEP}" 34 | Confere CEP ${CEP} 35 | 36 | Nenhum dado deve ser mostrado para o CEP "${CEP}" 37 | Confere o status code 200 38 | Confere endereço do CEP ${EMPTY} 39 | Confere bairro do CEP ${EMPTY} 40 | Confere cidade do CEP ${EMPTY} 41 | Confere UF do CEP ${EMPTY} 42 | Confere CEP ${CEP} 43 | 44 | #### PASSOS 45 | Conecta ao WebService 46 | Create Session consultaCEP ${HOST} 47 | 48 | Realiza requisição do CEP 49 | [Arguments] ${CEP_DESEJADO} 50 | ${RESPOSTA}= Get Request consultaCEP /${CEP_DESEJADO}/?app_key=${APP_KEY}&app_secret=${APP_SECRET} 51 | Log Resposta: ${RESPOSTA.text} 52 | Set Test Variable ${RESPOSTA} 53 | 54 | Confere o status code 55 | [Arguments] ${STATUS_ESPERADO} 56 | Log Status Code Retornado: ${RESPOSTA.status_code} -- Status Code Esperado: ${STATUS_ESPERADO} 57 | Should Be Equal As Strings ${RESPOSTA.status_code} ${STATUS_ESPERADO} 58 | 59 | Confere endereço do CEP 60 | [Arguments] ${ENDERECO} 61 | Dictionary Should Contain Item ${RESPOSTA.json()} endereco ${ENDERECO} 62 | 63 | Confere bairro do CEP 64 | [Arguments] ${BAIRRO} 65 | Dictionary Should Contain Item ${RESPOSTA.json()} bairro ${BAIRRO} 66 | 67 | Confere cidade do CEP 68 | [Arguments] ${CIDADE} 69 | Dictionary Should Contain Item ${RESPOSTA.json()} cidade ${CIDADE} 70 | 71 | Confere UF do CEP 72 | [Arguments] ${UF} 73 | Dictionary Should Contain Item ${RESPOSTA.json()} uf ${UF} 74 | 75 | Confere CEP 76 | [Arguments] ${CEP} 77 | Dictionary Should Contain Item ${RESPOSTA.json()} cep ${CEP} -------------------------------------------------------------------------------- /SuitePalestraGUTS/SuiteExemploWEB/ResourceCadastroQANinja.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library SeleniumLibrary 3 | Library FakerLibrary 4 | 5 | *** Variables *** 6 | ${URL} http://ninjainvoices.herokuapp.com/ 7 | ${NAVEGADOR} chrome 8 | ${TITULO_PAGINA} Ninja Invoices 9 | ${BOTAO_CADASTRO} xpath=.//*[@id="register"] 10 | ${TITULO_PAGINA_CADASTRO} css=#register_form > h5 11 | ${TEXTO_ESPERADO_PAGINA_CAD} Seja bem vindo ao Invoices faça seu cadastro aqui 12 | ${CAMPO_NOME} register_name 13 | ${CAMPO_EMAIL} register_email 14 | ${CAMPO_SENHA} register_password 15 | ${BOTAO_CAD_USUARIO} register_form 16 | ${TITULO_PAGINA_BOASVINDAS} xpath=.//*[@id="page_title"] 17 | ${NOME_USUARIO} Usuario Novo Teste 18 | ${EMAIL_INVALIDO} teste_email_invalido 19 | ${ALERTA} xpath=.//div[@class='alert alert-warning'] 20 | ${ALERTA_EMAIL_INVALIDO} Please enter valid e-mail address. 21 | 22 | *** Keywords *** 23 | Acessar Página Principal 24 | Open Browser ${URL} ${NAVEGADOR} 25 | Maximize Browser Window 26 | Sleep 1 27 | Title Should Be ${TITULO_PAGINA} 28 | 29 | Clicar em Cadastro 30 | Wait Until Element Is Enabled ${BOTAO_CADASTRO} 31 | Click Element ${BOTAO_CADASTRO} 32 | Wait Until Element Is Visible ${TITULO_PAGINA_CADASTRO} 33 | Element Text Should Be ${TITULO_PAGINA_CADASTRO} ${TEXTO_ESPERADO_PAGINA_CAD} 34 | 35 | Inserir Nome Completo 36 | Wait Until Element Is Enabled ${CAMPO_NOME} 37 | Input Text ${CAMPO_NOME} ${NOME_USUARIO} 38 | 39 | Inserir Email Válido 40 | Wait Until Element Is Enabled ${CAMPO_EMAIL} 41 | ${EMAIL_USUARIO}= FakerLibrary.Email 42 | Input Text ${CAMPO_EMAIL} ${EMAIL_USUARIO} 43 | 44 | Inserir Senha 45 | Wait Until Element Is Enabled ${CAMPO_SENHA} 46 | ${SENHA_USUARIO}= FakerLibrary.Password 8 True 47 | Input Password ${CAMPO_SENHA} ${SENHA_USUARIO} 48 | 49 | Submeter Cadastro 50 | Wait Until Element Is Enabled ${BOTAO_CAD_USUARIO} 51 | Sleep 1 52 | Submit Form ${BOTAO_CAD_USUARIO} 53 | 54 | Conferir Mensagem de Boas Vindas 55 | Wait Until Element Is Visible ${TITULO_PAGINA_BOASVINDAS} 56 | Sleep 2 57 | Page Should Contain Olá, ${NOME_USUARIO}, seja bem vindo ao Invoices. 58 | 59 | Inserir Email Inválido 60 | Wait Until Element Is Enabled ${CAMPO_EMAIL} 61 | Input Text ${CAMPO_EMAIL} ${EMAIL_INVALIDO} 62 | 63 | Conferir Mensagem de Alerta de Email Inválido 64 | Wait Until Element Is Enabled ${ALERTA} 65 | Sleep 2 66 | Element Text Should Be ${ALERTA} ${ALERTA_EMAIL_INVALIDO} -------------------------------------------------------------------------------- /ExemploLibraryXML/ResourceXML.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library OperatingSystem 3 | Library String 4 | Library XML 5 | 6 | *** Keywords *** 7 | Manipular e conferir XML 8 | ############ OPÇÃO 01 - Manipular como STRING ############ 9 | ### Pegue um XML no diretório, armazene em uma variável e manipule como STRING 10 | ${XML_CONTENT} Get File xmlBaseExemplo.xml 11 | ${XML_CONTENT} Replace String ${XML_CONTENT} ID_ANTES ID_DEPOIS 12 | Log ${XML_CONTENT} 13 | 14 | ############ OPÇÃO 02 - Manipular como XML ############ 15 | ### Pegando Elementos e Atributos com a library XML 16 | ${ELEMENTO} Get Element Text ${XML_CONTENT} xpath=.//idConsultante 17 | Log ${ELEMENTO} 18 | ${ATRIBUTO} Get Element Attribute ${XML_CONTENT} nome xpath=.//outroParametro[1] 19 | Log ${ATRIBUTO} 20 | 21 | ### Manipulando Elementos com a library XML 22 | ${XML_CONTENT} Remove Element ${XML_CONTENT} xpath=.//senhaConsultante 23 | Log Element ${XML_CONTENT} 24 | ${XML_CONTENT} Add Element ${XML_CONTENT} 9999999 xpath=.//consultarAvisosPendentes index=2 25 | Log Element ${XML_CONTENT} 26 | ${XML_CONTENT} Set Element Text ${XML_CONTENT} 02072019 xpath=.//dataReferencia 27 | Log Element ${XML_CONTENT} 28 | ${XML_CONTENT} Add Element ${XML_CONTENT} true xpath=.//consultarAvisosPendentes 29 | ${XML_CONTENT} Set Element Attribute ${XML_CONTENT} nome mayara xpath=.//outroParametro[3] 30 | ${XML_CONTENT} Set Element Attribute ${XML_CONTENT} valor QA xpath=.//outroParametro[3] 31 | Log Element ${XML_CONTENT} 32 | 33 | ### Após manipular, salve o XML e use como preferir 34 | Save Xml ${XML_CONTENT} meuXMLmanipulado.xml 35 | ${XML_FINAL} Get File meuXMLmanipulado.xml 36 | Log ${XML_FINAL} 37 | 38 | ### Conferências com a library XML 39 | Element Text Should Be ${XML_FINAL} ID_DEPOIS xpath=.//idConsultante 40 | Element Attribute Should Be ${XML_FINAL} nome atendimentoPlantao xpath=.//outroParametro[1] 41 | Element Attribute Should Be ${XML_FINAL} valor false xpath=.//outroParametro[1] 42 | Element Attribute Should Be ${XML_FINAL} nome urgente xpath=.//outroParametro[2] 43 | Element Attribute Should Be ${XML_FINAL} valor true xpath=.//outroParametro[2] 44 | Element Attribute Should Be ${XML_FINAL} nome mayara xpath=.//outroParametro[3] 45 | Element Attribute Should Be ${XML_FINAL} valor QA xpath=.//outroParametro[3] 46 | -------------------------------------------------------------------------------- /Demos/DemoAPI/Resource.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library RequestsLibrary 3 | Library Collections 4 | 5 | *** Variable *** 6 | ${HOST} https://webmaniabr.com/api/1/cep 7 | ${APP_KEY} njMf2EiyQ17g6C3vLUxk1yEsWTforVqf 8 | ${APP_SECRET} EgpTuUcM93IqHY8icgR3cK6Cn4bOlkQwSlfLd6ryMjrhhwMW 9 | 10 | *** Keywords *** 11 | #### DADO 12 | Que esteja conectado no webservice de consultas de CEP 13 | Conecta ao WebService 14 | 15 | #### QUANDO 16 | O usuário consultar o CEP "${CEP_CONSULTADO}" 17 | Realiza requisição do CEP ${CEP_CONSULTADO} 18 | 19 | #### ENTÃO 20 | Deve ser mostrado o endereço "${ENDERECO}" 21 | Confere o status code 200 22 | Confere endereço do CEP ${ENDERECO} 23 | 24 | Deve ser mostrado o bairro "${BAIRRO}" 25 | Confere bairro do CEP ${BAIRRO} 26 | 27 | Deve ser mostrada a cidade "${CIDADE}" 28 | Confere cidade do CEP ${CIDADE} 29 | 30 | Deve ser mostrada a UF "${UF}" 31 | Confere UF do CEP ${UF} 32 | 33 | Deve ser mostrado o CEP "${CEP}" 34 | Confere CEP ${CEP} 35 | 36 | ##Cenário 02 Depreciado em 12/04/2019 devido atualização na API 37 | # Nenhum dado deve ser mostrado para o CEP "${CEP}" 38 | # Confere o status code 200 39 | # Confere endereço do CEP ${EMPTY} 40 | # Confere bairro do CEP ${EMPTY} 41 | # Confere cidade do CEP ${EMPTY} 42 | # Confere UF do CEP ${EMPTY} 43 | # Confere CEP ${CEP} 44 | 45 | A mensagem de erro "${MSG_ERRO}" deve ser retornada 46 | Confere o status code 200 47 | Confere mensagem de erro ${MSG_ERRO} 48 | 49 | #### PASSOS 50 | Conecta ao WebService 51 | Create Session consultaCEP ${HOST} 52 | 53 | Realiza requisição do CEP 54 | [Arguments] ${CEP_DESEJADO} 55 | ${RESPOSTA}= Get Request consultaCEP /${CEP_DESEJADO}/?app_key=${APP_KEY}&app_secret=${APP_SECRET} 56 | Log Resposta: ${RESPOSTA.text} 57 | Set Test Variable ${RESPOSTA} 58 | 59 | Confere o status code 60 | [Arguments] ${STATUS_ESPERADO} 61 | Should Be Equal As Strings ${RESPOSTA.status_code} ${STATUS_ESPERADO} 62 | Log Status Code Retornado: ${RESPOSTA.status_code} -- Status Code Esperado: ${STATUS_ESPERADO} 63 | 64 | Confere endereço do CEP 65 | [Arguments] ${ENDERECO} 66 | Dictionary Should Contain Item ${RESPOSTA.json()} endereco ${ENDERECO} 67 | 68 | Confere bairro do CEP 69 | [Arguments] ${BAIRRO} 70 | Dictionary Should Contain Item ${RESPOSTA.json()} bairro ${BAIRRO} 71 | 72 | Confere cidade do CEP 73 | [Arguments] ${CIDADE} 74 | Dictionary Should Contain Item ${RESPOSTA.json()} cidade ${CIDADE} 75 | 76 | Confere UF do CEP 77 | [Arguments] ${UF} 78 | Dictionary Should Contain Item ${RESPOSTA.json()} uf ${UF} 79 | 80 | Confere CEP 81 | [Arguments] ${CEP} 82 | Dictionary Should Contain Item ${RESPOSTA.json()} cep ${CEP} 83 | 84 | Confere mensagem de erro 85 | [Arguments] ${MSG_ERRO} 86 | Dictionary Should Contain Item ${RESPOSTA.json()} error ${MSG_ERRO} 87 | -------------------------------------------------------------------------------- /SuiteCadastroQANinja/ResourceCadastroQANinja.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library Selenium2Library 3 | Library FakerLibrary 4 | 5 | *** Variables *** 6 | ${URL} http://ninjainvoices.herokuapp.com/ 7 | ${NAVEGADOR} chrome 8 | ${TITULO_PAGINA} Ninja Invoices 9 | ${BOTAO_CADASTRO} xpath=.//*[@id="register"] 10 | ${TITULO_PAGINA_CADASTRO} css=#register_form > h5 11 | ${TEXTO_ESPERADO_PAGINA_CAD} Seja bem vindo ao Invoices faça seu cadastro aqui 12 | ${CAMPO_NOME} register_name 13 | ${CAMPO_EMAIL} register_email 14 | ${CAMPO_SENHA} register_password 15 | ${BOTAO_CAD_USUARIO} register_form 16 | ${TITULO_PAGINA_BOASVINDAS} xpath=.//*[@id="page_title"] 17 | ${NOME_USUARIO} Usuario Novo Teste 18 | ${EMAIL_INVALIDO} teste_email_invalido 19 | ${ALERTA} xpath=.//div[@class='alert alert-warning'] 20 | ${ALERTA_EMAIL_INVALIDO} Please enter valid e-mail address. 21 | 22 | *** Keywords *** 23 | Acessar Página Principal 24 | Open Browser ${URL} ${NAVEGADOR} 25 | Title Should Be ${TITULO_PAGINA} 26 | 27 | Clicar em Cadastro 28 | Wait Until Element Is Enabled ${BOTAO_CADASTRO} 29 | Click Element ${BOTAO_CADASTRO} 30 | Wait Until Element Is Visible ${TITULO_PAGINA_CADASTRO} 31 | ${TEXTO_ATUAL_PAGINA_CAD}= Get Text ${TITULO_PAGINA_CADASTRO} 32 | Element Text Should Be ${TITULO_PAGINA_CADASTRO} ${TEXTO_ESPERADO_PAGINA_CAD} O Título atual [${TEXTO_ATUAL_PAGINA_CAD}] está errado. Esperado: [${TEXTO_ESPERADO_PAGINA_CAD}] 33 | 34 | Inserir Nome Completo 35 | Wait Until Element Is Enabled ${CAMPO_NOME} 36 | Input Text ${CAMPO_NOME} ${NOME_USUARIO} 37 | 38 | Inserir Email Válido 39 | Wait Until Element Is Enabled ${CAMPO_EMAIL} 40 | ${EMAIL_USUARIO}= FakerLibrary.Email 41 | Input Text ${CAMPO_EMAIL} ${EMAIL_USUARIO} 42 | 43 | Inserir Senha 44 | Wait Until Element Is Enabled ${CAMPO_SENHA} 45 | ${SENHA_USUARIO}= FakerLibrary.Password 8 True 46 | Input Password ${CAMPO_SENHA} ${SENHA_USUARIO} 47 | 48 | Submeter Cadastro 49 | Wait Until Element Is Enabled ${BOTAO_CAD_USUARIO} 50 | Submit Form ${BOTAO_CAD_USUARIO} 51 | 52 | Conferir Mensagem de Boas Vindas 53 | Wait Until Element Is Visible ${TITULO_PAGINA_BOASVINDAS} 54 | Page Should Contain Olá, ${NOME_USUARIO}, seja bem vindo ao Invoices. 55 | 56 | Inserir Email Inválido 57 | Wait Until Element Is Enabled ${CAMPO_EMAIL} 58 | Input Text ${CAMPO_EMAIL} ${EMAIL_INVALIDO} 59 | 60 | Conferir Mensagem de Alerta de Email Inválido 61 | Wait Until Element Is Enabled ${ALERTA} 62 | ${ALERTA_ATUAL}= Get Text ${ALERTA} 63 | Element Text Should Be ${ALERTA} ${ALERTA_EMAIL_INVALIDO} O Alerta atual [${ALERTA_ATUAL}] está errado. Esperado: [${ALERTA_EMAIL_INVALIDO}] 64 | 65 | 66 | 67 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/factory.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from suds.sudsobject import Object as SudsObject 16 | 17 | 18 | class _FactoryKeywords(object): 19 | 20 | def set_wsdl_object_attribute(self, object, name, value): 21 | """Sets the attribute of a WSDL object. 22 | 23 | Example: 24 | | ${order search request}= | Create Wsdl Object | OrderSearchRequest | | 25 | | Set Wsdl Object Attribute | ${order search request} | id | 4065 | 26 | """ 27 | self._assert_is_suds_object(object) 28 | getattr(object, name) 29 | setattr(object, name, value) 30 | 31 | def get_wsdl_object_attribute(self, object, name): 32 | """Gets the attribute of a WSDL object. 33 | 34 | Extendend variable syntax may be used to access attributes; however, 35 | some WSDL objects may have attribute names that are illegal in Python, 36 | necessitating this keyword. 37 | 38 | Example: 39 | | ${sale record}= | Call Soap Method | getLastSale | | 40 | | ${price}= | Get Wsdl Object Attribute | ${sale record} | Price | 41 | """ 42 | self._assert_is_suds_object(object) 43 | return getattr(object, name) 44 | 45 | def create_wsdl_object(self, type, *name_value_pairs): 46 | """Creates a WSDL object of the specified `type`. 47 | 48 | Requested `type` must be defined in the WSDL, in an import specified 49 | by the WSDL, or with `Add Doctor Import`. `type` is case sensitive. 50 | 51 | Example: 52 | | ${contact}= | Create Wsdl Object | Contact | | 53 | | Set Wsdl Object Attribute | ${contact} | Name | Kelly Newman | 54 | Attribute values can be set by passing the attribute name and value in 55 | pairs. This is equivalent to the two lines above: 56 | | ${contact}= | Create Wsdl Object | Contact | Name | Kelly Newman | 57 | """ 58 | if len(name_value_pairs) % 2 != 0: 59 | raise ValueError("Creating a WSDL object failed. There should be " 60 | "an even number of name-value pairs.") 61 | obj = self._client().factory.create(type) 62 | for i in range(0, len(name_value_pairs), 2): 63 | self.set_wsdl_object_attribute(obj, name_value_pairs[i], name_value_pairs[i + 1]) 64 | return obj 65 | 66 | # private 67 | 68 | def _assert_is_suds_object(self, object): 69 | if not isinstance(object, SudsObject): 70 | raise ValueError("Object must be a WSDL object (suds.sudsobject.Object).") 71 | -------------------------------------------------------------------------------- /ExemploAPI_ServeRest/Exemplo_API_ServeRest.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Documentation Testes utilizando as novas keywords da RequestsLibrary na versão 8 3 | Library RequestsLibrary 4 | Library Collections 5 | Library FakerLibrary locale=pt_br 6 | 7 | 8 | *** Variables *** 9 | ${ALIAS} API_serverest 10 | 11 | 12 | *** Test Cases *** 13 | Testar a API pública de estudos serverest 14 | Iniciar sessão na API serverest 15 | Cadastrar usuário de teste 16 | Obter Token 17 | Cadastrar um produto 18 | Listar o produto cadastrado 19 | 20 | 21 | *** Keywords *** 22 | Cria dados aleatórios do usuário 23 | ${RANDOM_NOME_FIRST} FakerLibrary.First Name 24 | ${RANDOM_NOME_LAST} FakerLibrary.Last Name 25 | ${RANDOM_EMAIL} FakerLibrary.Email 26 | ${RANDOM_PWD} FakerLibrary.Password 27 | ${USUARIO} Create Dictionary nome=${RANDOM_NOME_FIRST} ${RANDOM_NOME_LAST} email=${RANDOM_EMAIL} senha=${RANDOM_PWD} 28 | Set Suite Variable ${USUARIO} 29 | 30 | Iniciar sessão na API serverest 31 | ${HEADERS} Create Dictionary Content-Type=application/json 32 | Create Session alias=${ALIAS} url=https://serverest.dev headers=${HEADERS} disable_warnings=1 33 | 34 | Cadastrar usuário de teste 35 | Cria dados aleatórios do usuário 36 | ${BODY} Create Dictionary nome=${USUARIO.nome} email=${USUARIO.email} password=${USUARIO.senha} administrador=true 37 | ${RESPONSE} POST On Session alias=${ALIAS} url=usuarios json=${BODY} 38 | Log Resposta Retornada: ${\n}${RESPONSE.text} 39 | 40 | Obter Token 41 | ${BODY} Create Dictionary email=${USUARIO.email} password=${USUARIO.senha} 42 | ${RESPONSE} POST On Session alias=${ALIAS} url=login json=${BODY} 43 | Log Resposta Retornada: ${\n}${RESPONSE.text} 44 | Dictionary Should Contain Item ${RESPONSE.json()} message Login realizado com sucesso 45 | ${TOKEN} Get From Dictionary ${RESPONSE.json()} authorization 46 | Set Suite Variable ${TOKEN} 47 | 48 | Cadastrar um produto 49 | ${RANDOM_PROD} FakerLibrary.Word 50 | Set Suite Variable ${RANDOM_PROD} 51 | ${BODY} Create Dictionary nome=${RANDOM_PROD} preco=155 descricao=meu produto de teste quantidade=10 52 | ${HEADERS} Create Dictionary Authorization=${TOKEN} 53 | ${RESPONSE} POST On Session alias=${ALIAS} url=produtos json=${BODY} headers=${HEADERS} 54 | Log Resposta Retornada: ${\n}${RESPONSE.text} 55 | Dictionary Should Contain Item ${RESPONSE.json()} message Cadastro realizado com sucesso 56 | ${ID_PRODUTO_CADASTRADO} Get From Dictionary ${RESPONSE.json()} _id 57 | Set Suite Variable ${ID_PRODUTO_CADASTRADO} 58 | 59 | Listar o produto cadastrado 60 | ${HEADERS} Create Dictionary Authorization=${TOKEN} 61 | ${RESPONSE} GET On Session alias=${ALIAS} url=produtos/${ID_PRODUTO_CADASTRADO} headers=${HEADERS} 62 | Log Resposta Retornada: ${\n}${RESPONSE.text} 63 | Dictionary Should Contain Item ${RESPONSE.json()} nome ${RANDOM_PROD} 64 | Dictionary Should Contain Item ${RESPONSE.json()} preco 155 65 | Dictionary Should Contain Item ${RESPONSE.json()} descricao meu produto de teste 66 | Dictionary Should Contain Item ${RESPONSE.json()} quantidade 10 67 | Dictionary Should Contain Key ${RESPONSE.json()} _id 68 | -------------------------------------------------------------------------------- /RabbitMQ/ResourceRabbitMQ.robot: -------------------------------------------------------------------------------- 1 | *** Settings *** 2 | Library ./RabbitMQCustom.py 3 | Library RequestsLibrary 4 | Library Collections 5 | 6 | *** Keywords *** 7 | Conectar no RabbitMQ 8 | [Documentation] Efetua a conexão com o RabbitMQ. 9 | [Arguments] ${RABBIT_HOST} ${RABBIT_PORT} ${RABBIT_USER} ${RABBIT_PASSWORD} ${RABBIT_ALIAS}=rmq_http 10 | Connect To RabbitMQ host=${RABBIT_HOST} 11 | ... port=${RABBIT_PORT} 12 | ... username=${RABBIT_USER} 13 | ... password=${RABBIT_PASSWORD} 14 | ... alias=${RABBIT_ALIAS} 15 | 16 | Criar fila com prioridade no RabbitMQ 17 | [Documentation] Cria uma fila com prioridade. Default prioridade=5. 18 | [Arguments] ${FILA} ${PRIORIDADE}=${5} 19 | ${ARGUMENTS} Create Dictionary x-max-priority=${PRIORIDADE} 20 | Create Queues By Name ${FILA} arguments=${ARGUMENTS} 21 | 22 | Criar filas com prioridade no RabbitMQ 23 | [Documentation] Cria as filas listadas na lista enviada, com prioridade. Default prioridade=5. 24 | [Arguments] @{FILAS_CRIAR} ${PRIORIDADE}=${5} 25 | FOR ${FILA} IN @{FILAS_CRIAR} 26 | Criar fila com prioridade no RabbitMQ ${FILA} ${PRIORIDADE} 27 | END 28 | 29 | Limpar todas as filas do RabbitMQ 30 | [Documentation] Limpa (purge) as filas listadas na lista enviada. 31 | [Arguments] @{FILAS_LIMPAR} 32 | FOR ${FILA} IN @{FILAS_LIMPAR} 33 | Purge Messages By Queue ${FILA} 34 | END 35 | 36 | Fechar conexão com o RabbitMQ 37 | [Documentation] Encerra a conexão com o RabbitMQ. 38 | Disconnect From RabbitMQ 39 | 40 | ###### Requisições 41 | Realizar requisição POST no RabbitMQ 42 | [Documentation] Publica uma mensagem em uma determinada fila sem envio de headers. 43 | [Arguments] ${MENSAGEM} ${FILA} 44 | &{PROPERTIES} Create Dictionary delivery_mode=${1} 45 | ${PUBLISH} Publish Message By Name queue=${FILA} msg=${MENSAGEM} properties=${PROPERTIES} 46 | Verificar sucesso no publish ${PUBLISH} 47 | 48 | Realizar requisição POST com HEADERS no RabbitMQ 49 | [Documentation] Publica uma mensagem em uma determinada fila com envio de headers. 50 | [Arguments] ${MENSAGEM} ${FILA} ${HEADERS} 51 | &{PROPERTIES} Create Dictionary delivery_mode=${1} headers=${HEADERS} 52 | ${PUBLISH} Publish Message By Name queue=${FILA} msg=${MENSAGEM} properties=${PROPERTIES} 53 | Verificar sucesso no publish ${PUBLISH} 54 | 55 | Verificar sucesso no publish 56 | [Documentation] Verifica se houve sucesso em um publish realizado. 57 | [Arguments] ${PUBLISH} 58 | Log Dictionary ${PUBLISH} 59 | ${ROUTED} Get From Dictionary ${PUBLISH} routed 60 | Should be True ${ROUTED} msg=Não foi possível publicar no RabbitMQ. Verifique! 61 | 62 | Realizar requisição GET de uma mensagem no RabbitMQ 63 | [Documentation] Pega a primeira mensagem da fila especificada. Faz tentativas de obtê-la até um limite de tempo. Default limte_wait=75. 64 | [Arguments] ${FILA} ${LIMITE_WAIT}=75 65 | FOR ${SEGUNDO} IN RANGE 0 ${LIMITE_WAIT} 66 | ${RESPOSTA} Run Keyword And Ignore Error Get Messages by Queue ${FILA} 1 67 | ${TAMANHO} Get Length ${RESPOSTA[1]} 68 | Exit For Loop If ${TAMANHO} > 0 and '${RESPOSTA[0]}'=='PASS' 69 | Run Keyword If '${RESPOSTA[1]}' == 'CannotSendRequest: Request-sent' Sleep 3s ELSE Sleep 0.2s 70 | END 71 | Log Mensagem retornada:${\n}${RESPOSTA[1]} 72 | Validar se retornou mensagens ${RESPOSTA[1]} ${FILA} 73 | ${RESPOSTA} To Json ${RESPOSTA[1]["payload"]} 74 | [Return] ${RESPOSTA} 75 | 76 | Realizar requisição GET de várias mensagens no RabbitMQ 77 | [Documentation] Pega as primeiras N mensagens da fila especificada. 78 | [Arguments] ${FILA} ${COUNT} 79 | ${RESPOSTA} Get Messages by Queue ${FILA} ${COUNT} 80 | Log Mensagens retornadas:${\n}${RESPOSTA} 81 | Validar se retornou mensagens ${RESPOSTA} ${FILA} 82 | ${RESPOSTA} To Json ${RESPOSTA[0]["payload"]} 83 | [Return] ${RESPOSTA} 84 | 85 | Validar se retornou mensagens 86 | [Arguments] ${RESPOSTA} ${FILA} 87 | ${TAMANHO} Get Length ${RESPOSTA[1]} 88 | Run Keyword If ${TAMANHO} == 0 Fail Não há mensagens na fila [${FILA}]. Verifique! 89 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/soaplogging.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import xml.dom.minidom 16 | from xml.parsers.expat import ExpatError 17 | from suds.plugin import MessagePlugin 18 | from robot.api import logger 19 | from .utils import * 20 | 21 | 22 | class _SoapLogger(MessagePlugin): 23 | 24 | def __init__(self): 25 | self._sent = None 26 | self._received = None 27 | self.log = True 28 | self.prettyxml = True 29 | self._indent = 2 30 | 31 | def sending(self, context): 32 | self._sent = context.envelope 33 | self._received = None 34 | if self.log: 35 | logger.info('Sending:\n%s' % self.last_sent(self.prettyxml)) 36 | 37 | def last_sent(self, prettyxml=False): 38 | # possible that text inserted into the post body, making it invalid XML 39 | try: 40 | return self._prettyxml(self._sent) if prettyxml else self._sent 41 | except ExpatError: 42 | return self._sent 43 | 44 | def received(self, context): 45 | self._received = context.reply 46 | if self.log: 47 | logger.info('Received:\n%s' % self.last_received(self.prettyxml)) 48 | 49 | def last_received(self, prettyxml=False): 50 | return self._prettyxml(self._received) if prettyxml else self._received 51 | 52 | def set_indent(self, indent): 53 | try: 54 | self._indent = int(indent) 55 | except ValueError: 56 | raise ValueError("Cannot convert indent value '%s' to an integer" 57 | % indent) 58 | 59 | def _prettyxml(self, xml_string): 60 | dom = xml.dom.minidom.parseString(xml_string) 61 | return dom.toprettyxml(indent=(self._indent * " ")) 62 | 63 | 64 | class _SoapLoggingKeywords(object): 65 | 66 | def set_soap_logging(self, log, prettyxml=None, indent=None): 67 | """Sets whether to log the request and response for the current client. 68 | 69 | By default, the message sent and received is logged at level INFO, 70 | pretty-formatted with an indent of 2 spaces per level. Setting `log` 71 | to false will disable logging, reducing the size of the log. Boolean 72 | option `prettyxml` controls whether the XML is pretty-formatted. 73 | `indent` should be the number of spaces to indent per level. Leaving 74 | `prettyxml` or `indent` at the default value of None will preserve the 75 | previous settings. Returns the current value of log. 76 | 77 | Examples: 78 | | ${old log value} | Set Soap Logging | False | | 79 | | Call Soap Method | lengthyResponse | | | 80 | | Set Soap Logging | True | True | 4 | 81 | """ 82 | new_value = to_bool(log) 83 | soap_logger = self._get_soap_logger() 84 | if soap_logger: 85 | old_value = soap_logger.log 86 | else: 87 | soap_logger = self._add_soap_logger() 88 | old_value = False 89 | soap_logger.log = new_value 90 | if not prettyxml is None: 91 | soap_logger.prettyxml = to_bool(prettyxml) 92 | if not indent is None: 93 | soap_logger.set_indent(indent) 94 | return old_value 95 | 96 | def get_last_sent(self): 97 | """Gets the message text last sent. 98 | 99 | Unless a plugin is used to modify the message, it will always be a XML 100 | document.""" 101 | soap_logger = self._get_soap_logger(True) 102 | return soap_logger.last_sent(False) 103 | 104 | def get_last_received(self): 105 | """Gets the XML last received.""" 106 | soap_logger = self._get_soap_logger(True) 107 | return soap_logger.last_received(False) 108 | 109 | # private 110 | 111 | def _get_soap_logger(self, required=False): 112 | plugins = self._client().options.plugins 113 | matches = [x for x in plugins if isinstance(x, _SoapLogger)] 114 | if matches: 115 | return matches[0] 116 | else: 117 | if required: 118 | raise RuntimeError("The SudsLibrary SOAP logging message plugin has been removed.") 119 | return None 120 | 121 | def _add_soap_logger(self): 122 | client = self._client() 123 | plugins = client.options.plugins 124 | soap_logger = _SoapLogger() 125 | plugins.append(soap_logger) 126 | client.set_options(plugins=plugins) 127 | return soap_logger 128 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/proxy.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from suds import WebFault 16 | from suds import byte_str 17 | from suds.sax.text import Raw 18 | from .utils import * 19 | import socket 20 | 21 | 22 | class RawSoapMessage(object): 23 | 24 | def __init__(self, string): 25 | if isinstance(string, bytes): 26 | self.message = string.decode() 27 | else: 28 | self.message = str(string) 29 | 30 | def __str__(self): 31 | return self.message 32 | 33 | def __unicode__(self): 34 | return self.message 35 | 36 | 37 | class _ProxyKeywords(object): 38 | 39 | def call_soap_method(self, name, *args): 40 | """Calls the SOAP method with the given `name` and `args`. 41 | 42 | Returns a Python object graph or SOAP envelope as a XML string 43 | depending on the client options. 44 | """ 45 | 46 | return self._call(None, None, False, name, *args) 47 | 48 | def specific_soap_call(self, service, port, name, *args): 49 | """Calls the SOAP method overriding client settings. 50 | 51 | If there is only one service specified then `service` is ignored. 52 | `service` and `port` can be either by name or index. If only `port` or 53 | `service` need to be specified, leave the other one ${None} or 54 | ${EMPTY}. The index is the order of appearence in the WSDL starting 55 | with 0. 56 | 57 | Returns a Python object graph or SOAP envelope as a XML string 58 | depending on the client options. 59 | """ 60 | 61 | return self._call(service, port, False, name, *args) 62 | 63 | def call_soap_method_expecting_fault(self, name, *args): 64 | """Calls the SOAP method expecting the server to raise a fault. 65 | 66 | Fails if the server does not raise a fault. Returns a Python object 67 | graph or SOAP envelope as a XML string depending on the client 68 | options. 69 | 70 | A fault has the following attributes:\n 71 | | faultcode | required | 72 | | faultstring | required | 73 | | faultactor | optional | 74 | | detail | optional | 75 | """ 76 | return self._call(None, None, True, name, *args) 77 | 78 | def create_raw_soap_message(self, message): 79 | """Returns an object that can used in lieu of SOAP method arguments. 80 | 81 | `message` should be an entire SOAP message as a string. The object 82 | returned can be used in lieu of *args for `Call Soap Method`, `Call 83 | Soap Method Expecting Fault`, and `Specific Soap Call`. 84 | 85 | Example:\n 86 | | ${message}= | Create Raw Soap Message | | 87 | | Call Soap Method | addContact | ${message} | 88 | """ 89 | return RawSoapMessage(message) 90 | 91 | # private 92 | 93 | def _call(self, service, port, expect_fault, name, *args): 94 | client = self._client() 95 | self._backup_options() 96 | if service or (service == 0): 97 | client.set_options(service=parse_index(service)) 98 | if port or (port == 0): 99 | client.set_options(port=parse_index(port)) 100 | method = getattr(client.service, name) 101 | received = None 102 | try: 103 | if len(args) == 1 and isinstance(args[0], RawSoapMessage): 104 | message = byte_str(args[0].message) 105 | received = method(__inject={'msg': message}) 106 | else: 107 | received = method(*args) 108 | if expect_fault: 109 | raise AssertionError('The server did not raise a fault.') 110 | except WebFault as e: 111 | if not expect_fault: 112 | raise e 113 | received = e.fault 114 | finally: 115 | self._restore_options() 116 | return_xml = self._get_external_option("return_xml", False) 117 | if return_xml: 118 | received = self.get_last_received() 119 | return received 120 | 121 | # private 122 | 123 | def _backup_options(self): 124 | options = self._client().options 125 | self._old_options = dict([[n, getattr(options, n)] for n in ('service', 'port')]) 126 | if self._global_timeout: 127 | self._old_timeout = socket.getdefaulttimeout() 128 | 129 | def _restore_options(self): 130 | self._client().set_options(**self._old_options) 131 | # restore the default socket timeout because suds does not 132 | if self._global_timeout: 133 | socket.setdefaulttimeout(self._old_timeout) 134 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/clientmanagement.py: -------------------------------------------------------------------------------- 1 | # Copyright 2012 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | import os 16 | import urllib.request, urllib.parse, urllib.error 17 | from suds.xsd.doctor import ImportDoctor 18 | from suds.transport.http import HttpAuthenticated 19 | from urllib.parse import urlparse 20 | from suds.client import Client 21 | from .utils import * 22 | 23 | 24 | class _ClientManagementKeywords(object): 25 | 26 | def create_soap_client(self, url_or_path, alias=None, autoblend=False, timeout='90 seconds', username=None, 27 | password=None, auth_type='STANDARD'): 28 | """Loads a WSDL from the given URL/path and creates a Suds SOAP client. 29 | 30 | Returns the index of this client instance which can be used later to 31 | switch back to it. See `Switch Soap Client` for example. 32 | 33 | Optional alias is an alias for the client instance and it can be used 34 | for switching between clients (just as index can be used). See `Switch 35 | Soap Client` for more details. 36 | 37 | `username` and `password` are needed if the WSDL is on a server 38 | requiring basic authentication. `auth_type` selects the authentication 39 | scheme to use. See `Set Http Authentication` for more information. 40 | 41 | Autoblend ensures that the schema(s) defined within the WSDL import 42 | each other. 43 | 44 | `timeout` sets the timeout for SOAP requests and must be given in 45 | Robot Framework's time format (e.g. '1 minute', '2 min 3 s', '4.5'). 46 | 47 | Examples: 48 | | Create Soap Client | http://localhost:8080/ws/Billing.asmx?WSDL | 49 | | Create Soap Client | ${CURDIR}/../wsdls/tracking.wsdl | 50 | """ 51 | url = self._get_url(url_or_path) 52 | autoblend = to_bool(autoblend) 53 | kwargs = {'autoblend': autoblend} 54 | if username: 55 | password = password if password is not None else "" 56 | transport = self._get_transport(auth_type, username, password) 57 | kwargs['transport'] = transport 58 | imports = self._imports 59 | if imports: 60 | self._log_imports() 61 | kwargs['doctor'] = ImportDoctor(*imports) 62 | client = Client(url, **kwargs) 63 | index = self._add_client(client, alias) 64 | self._set_soap_timeout(timeout) 65 | return index 66 | 67 | def switch_soap_client(self, index_or_alias): 68 | """Switches between clients using index or alias. 69 | 70 | Index is returned from `Create Soap Client` and alias can be given to 71 | it. 72 | 73 | Example: 74 | | Create Soap Client | http://localhost:8080/Billing?wsdl | Billing | 75 | | Create Soap Client | http://localhost:8080/Marketing?wsdl | Marketing | 76 | | Call Soap Method | sendSpam | | 77 | | Switch Soap Client | Billing | # alias | 78 | | Call Soap Method | sendInvoices | | 79 | | Switch Soap Client | 2 | # index | 80 | 81 | Above example expects that there was no other clients created when 82 | creating the first one because it used index '1' when switching to it 83 | later. If you aren't sure about that you can store the index into 84 | a variable as below. 85 | 86 | | ${id} = | Create Soap Client | ... | 87 | | # Do something ... | | | 88 | | Switch Soap Client | ${id} | | 89 | """ 90 | self._cache.switch(index_or_alias) 91 | 92 | # PyAPI 93 | 94 | def _client(self): 95 | """Returns the current suds.client.Client instance.""" 96 | return self._cache.current 97 | 98 | def _add_client(self, client, alias=None): 99 | """Puts a client into the cache and returns the index. 100 | 101 | The added client becomes the current one.""" 102 | client.set_options(faults=True) 103 | self._logger.info('Using WSDL at %s%s' % (client.wsdl.url, client)) 104 | self._imports = [] 105 | index = self._cache.register(client, alias) 106 | self.set_soap_logging(True) 107 | return index 108 | 109 | # private 110 | 111 | def _log_imports(self): 112 | if self._imports: 113 | msg = "Using Imports for ImportDoctor:" 114 | for imp in self._imports: 115 | msg += "\n Namespace: '%s' Location: '%s'" % (imp.ns, imp.location) 116 | for ns in imp.filter.tns: 117 | msg += "\n Filtering for namespace '%s'" % ns 118 | self._logger.info(msg) 119 | 120 | def _get_url(self, url_or_path): 121 | if not len(urlparse(url_or_path).scheme) > 1: 122 | if not os.path.isfile(url_or_path): 123 | raise IOError("File '%s' not found." % url_or_path) 124 | url_or_path = 'file:' + urllib.request.pathname2url(url_or_path) 125 | return url_or_path 126 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/wsse.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from .utils import * 16 | from suds.wsse import Security 17 | from suds.wsse import Token 18 | from suds.wsse import Timestamp 19 | from suds.wsse import UsernameToken 20 | from suds.sax.element import Element 21 | from random import random 22 | from hashlib import sha1 23 | import base64 24 | import re 25 | from datetime import timedelta, datetime 26 | import robot 27 | 28 | 29 | TEXT_TYPE = 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText' 30 | DIGEST_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordDigest" 31 | BASE64_ENC_TYPE = "http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary" 32 | WSSENS = \ 33 | ('wsse', 34 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd') 35 | WSUNS = \ 36 | ('wsu', 37 | 'http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd') 38 | 39 | 40 | def iso_utc(dt=None): 41 | if dt is None: 42 | dt = datetime.utcnow() 43 | # precision only to milliseconds per WS-Security recommendation 44 | return re.sub(r'(?<=\.\d{3})\d+', '', dt.isoformat()) + 'Z' 45 | 46 | 47 | class AutoTimestamp(Timestamp): 48 | 49 | def __init__(self, validity=None): 50 | Token.__init__(self) 51 | self.validity = validity 52 | 53 | def xml(self): 54 | self.created = datetime.utcnow() 55 | root = Element("Timestamp", ns=WSUNS) 56 | created = Element('Created', ns=WSUNS) 57 | created.setText(iso_utc(self.created)) 58 | root.append(created) 59 | if self.validity is not None: 60 | self.expires = self.created + timedelta(seconds=self.validity) 61 | expires = Element('Expires', ns=WSUNS) 62 | expires.setText(iso_utc(self.expires)) 63 | root.append(expires) 64 | return root 65 | 66 | 67 | class AutoUsernameToken(UsernameToken): 68 | 69 | def __init__(self, username=None, password=None, setcreated=False, 70 | setnonce=False, digest=False): 71 | UsernameToken.__init__(self, username, password) 72 | self.autosetcreated = setcreated 73 | self.autosetnonce = setnonce 74 | self.digest = digest 75 | 76 | def setnonce(self, text=None): 77 | if text is None: 78 | hash = sha1() 79 | hash.update(str(random())) 80 | hash.update(iso_utc()) 81 | self.nonce = hash.hexdigest() 82 | else: 83 | self.nonce = text 84 | 85 | def xml(self): 86 | if self.digest and self.password is None: 87 | raise RuntimeError("Cannot generate password digest without the password.") 88 | if self.autosetnonce: 89 | self.setnonce() 90 | if self.autosetcreated: 91 | self.setcreated() 92 | root = Element('UsernameToken', ns=WSSENS) 93 | u = Element('Username', ns=WSSENS) 94 | u.setText(self.username) 95 | root.append(u) 96 | if self.password is not None: 97 | password = self.password 98 | if self.digest: 99 | password = self.get_digest() 100 | p = Element('Password', ns=WSSENS) 101 | p.setText(password) 102 | p.set('Type', DIGEST_TYPE if self.digest else TEXT_TYPE) 103 | root.append(p) 104 | if self.nonce is not None: 105 | n = Element('Nonce', ns=WSSENS) 106 | n.setText(base64.encodestring(self.nonce)[:-1]) 107 | n.set('EncodingType', BASE64_ENC_TYPE) 108 | root.append(n) 109 | if self.created: 110 | c = Element('Created', ns=WSUNS) 111 | c.setText(iso_utc(self.created)) 112 | root.append(c) 113 | return root 114 | 115 | def get_digest(self): 116 | nonce = str(self.nonce) if self.nonce else "" 117 | created = iso_utc(self.created) if self.created else "" 118 | password = str(self.password) 119 | message = nonce + created + password 120 | return base64.encodestring(sha1(message).digest())[:-1] 121 | 122 | 123 | class _WsseKeywords(object): 124 | 125 | def apply_security_timestamp(self, duration=None): 126 | """Applies a Timestamp element to future requests valid for the given `duration`. 127 | 128 | The SOAP header will contain a Timestamp element as specified in the 129 | WS-Security extension. The Created and Expires values are updated 130 | every time a request is made. If `duration` is None, the Expires 131 | element will be absent. 132 | 133 | `duration` must be given in Robot Framework's time format (e.g. 134 | '1 minute', '2 min 3 s', '4.5'). 135 | 136 | Example: 137 | | Apply Security Timestamp | 5 min | 138 | """ 139 | if duration is not None: 140 | duration = robot.utils.timestr_to_secs(duration) 141 | wsse = self._get_wsse() 142 | wsse.tokens = [x for x in wsse.tokens if not isinstance(x, Timestamp)] 143 | wsse.tokens.insert(0, AutoTimestamp(duration)) 144 | self._client().set_options(wsse=wsse) 145 | 146 | def apply_username_token(self, username, password=None, setcreated=False, 147 | setnonce=False, digest=False): 148 | """Applies a UsernameToken element to future requests. 149 | 150 | The SOAP header will contain a UsernameToken element as specified in 151 | Username Token Profile 1.1 that complies with Basic Security Profile 152 | 1.1. The Created and Nonce values, if enabled, are generated 153 | automatically and updated every time a request is made. If `digest` is 154 | True, a digest derived from the password is sent. 155 | 156 | Example: 157 | | Apply Username Token | ying | myPa$$word | 158 | """ 159 | setcreated = to_bool(setcreated) 160 | setnonce = to_bool(setnonce) 161 | digest = to_bool(digest) 162 | if digest and password is None: 163 | raise RuntimeError("Password is required when digest is True.") 164 | token = AutoUsernameToken(username, password, setcreated, setnonce, 165 | digest) 166 | wsse = self._get_wsse() 167 | wsse.tokens = [x for x in wsse.tokens if not isinstance(x, UsernameToken)] 168 | wsse.tokens.append(token) 169 | self._client().set_options(wsse=wsse) 170 | 171 | # private 172 | 173 | def _get_wsse(self, create=True): 174 | wsse = self._client().options.wsse 175 | if wsse is None and create: 176 | wsse = Security() 177 | wsse.mustUnderstand = '1' 178 | return wsse 179 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/MySudsLibrary.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from robot.utils import ConnectionCache 16 | from MyCustomSudsLibrary.monkeypatches import * 17 | from MyCustomSudsLibrary.factory import _FactoryKeywords 18 | from MyCustomSudsLibrary.clientmanagement import _ClientManagementKeywords 19 | from MyCustomSudsLibrary.options import _OptionsKeywords 20 | from MyCustomSudsLibrary.proxy import _ProxyKeywords 21 | from MyCustomSudsLibrary.soaplogging import _SoapLoggingKeywords 22 | from MyCustomSudsLibrary.wsse import _WsseKeywords 23 | from suds import null 24 | from robot.api import logger 25 | from robot.libraries.BuiltIn import BuiltIn 26 | import traceback 27 | import weakref 28 | 29 | 30 | class MySudsLibrary(_ClientManagementKeywords, _FactoryKeywords, 31 | _OptionsKeywords, _ProxyKeywords, _SoapLoggingKeywords, 32 | _WsseKeywords): 33 | """SudsLibrary is a library for functional testing of SOAP-based web 34 | services. 35 | 36 | SudsLibrary is based on [https://fedorahosted.org/suds/|Suds], a dynamic 37 | SOAP 1.1 client. 38 | 39 | == Case Sensitivy in SudsLibrary == 40 | Many things in the world of SOAP are case-sensitive. This includes method 41 | names, WSDL object names and attributes, and service or port names. 42 | 43 | == Creating and Configuring a Client == 44 | If necessary, use keywords `Bind Schema To Location` or `Add Doctor 45 | Import`. These are rarely needed. Next, `Create Soap Client` to create a Suds 46 | client. The output from this keyword contains useful information including 47 | available types and methods. Next, use other keywords to configure the 48 | client as necessary. `Set Location` is the most commonly needed keyword. 49 | 50 | == Working with WSDL Objects == 51 | When Suds digests a WSDL, it creates dynamic types to represent the complex 52 | types defined by a WSDL or its imports. These types are listed in the 53 | output of `Create Soap Client`. WSDL objects are used as method arguments, 54 | attribute values of other WSDL objects, and return values. `Create Wsdl 55 | Object` is used to create instances of WSDL object types. To see what the 56 | structure of a WSDL object is, you can do this: 57 | | ${obj}= | Create Wsdl Object | someObject | 58 | | ${obj as str}= | Convert To String | ${obj} | 59 | | Log | ${obj as str} | | 60 | The same technique can be used to analyze a response object. It may also 61 | help to use a tool such as Eclipse or SoapUI to comprehend the structures. 62 | 63 | === Getting WSDL Object Attributes === 64 | Getting a WSDL object's attribute value may be done with `Get Wsdl Object 65 | Attribute` or extended variable syntax*. Keywords from other libraries, such 66 | as _BuiltIn_ and _Collections_ may be used to verify attribute values. 67 | Examples: 68 | | ${name}= | Get Wsdl Object Attribute | ${person} | name | 69 | | Should Be Equal | ${person.name} | Bob | | 70 | 71 | === Setting WSDL Object Attributes === 72 | Setting a WSDL object's attribute value may be done with `Set Wsdl Object 73 | Attribute` or extended variable syntax*. `Set Wsdl Object Attribute` 74 | verifies the argument is an object of the correct type and the attribute 75 | exists. 76 | | Set Wsdl Object Attribute | ${person} | name | Tia | 77 | | ${person.name}= | Set Variable | Tia | | 78 | 79 | * In order to use extended variable syntax, the attribute name must consist 80 | of only letters, numbers, and underscores. 81 | 82 | == Example Test == 83 | The following simple example demonstrates verifying the return value using 84 | keywords in this library and in the `BuiltIn` and `Collections` libraries. 85 | You can run this test because it uses a public web service. 86 | 87 | | Create Soap Client | http://www.webservicex.net/Statistics.asmx?WSDL | | | 88 | | ${dbl array}= | Create Wsdl Object | ArrayOfDouble | | 89 | | Append To List | ${dbl array.double} | 2.0 | | 90 | | Append To List | ${dbl array.double} | 3.0 | | 91 | | ${result}= | Call Soap Method | GetStatistics | ${dbl array} | 92 | | Should Be Equal As Numbers | ${result.Average} | 2.5 | | 93 | 94 | The definition of type ArrayOfDouble: 95 | | 96 | | 97 | | 98 | | 99 | | 100 | Note that the attribute name on the ArrayOfDouble-type that is the list of 101 | numbers is the singular "double". Outside of the WSDL, the structure can 102 | also be seen in the output of Create Wsdl Object: 103 | | ${dbl array} = (ArrayOfDouble){ 104 | | double[] = 105 | | } 106 | 107 | The relevant part of the WSDL defining the parameters to the method: 108 | | 109 | | 110 | | 111 | | 112 | | 113 | | 114 | | 115 | The definition of this method appears in the output of Create Soap Client 116 | as: 117 | | GetStatistics(ArrayOfDouble X, ) 118 | 119 | == Passing Explicit NULL Values == 120 | If you have a service that takes NULL values for required parameters or 121 | you want to pass NULL for optional object attributes, you simply need to 122 | set the value to ${SUDS_NULL}. You need to use ${SUDS_NULL} instead of 123 | ${None} because None is interpreted by the marshaller as not having a 124 | value. The soap message will contain an empty (and xsi:nil="true" if node 125 | defined as nillable). ${SUDS_NULL} is defined during library 126 | initialization, so editors like RIDE will not show it as defined. 127 | 128 | == Extending SudsLibrary == 129 | There may be times where Suds/SudsLibrary does not work using the library 130 | keywords alone. Extending the library instead of writing a custom one will 131 | allow you to use the existing keywords in SudsLibrary. 132 | 133 | There are two methods useful for extending SudsLibrary: 134 | | _client() 135 | | _add_client(client, alias=None) 136 | The first can be used to access the current instance of 137 | suds.client.Client. The second can be used to put a client into the client 138 | cache that you have instantiated. 139 | 140 | Here is an example demonstrating how to implement a keyword that adds a 141 | MessagePlugin to the current Suds client (based on the [https://fedorahosted.org/suds/wiki/Documentation#MessagePlugin|Suds documentation]): 142 | | from robot.libraries.BuiltIn import BuiltIn 143 | | from suds.plugin import MessagePlugin 144 | | 145 | | class _MyPlugin(MessagePlugin): 146 | | def marshalled(self, context): 147 | | body = context.envelope.getChild('Body') 148 | | foo = body[0] 149 | | foo.set('id', '12345') 150 | | foo.set('version', '2.0') 151 | | 152 | | class SudsLibraryExtensions(object): 153 | | def attach_my_plugin(self): 154 | | client = BuiltIn().get_library_instance("SudsLibrary")._client() 155 | | # prepend so SudsLibrary's plugin is left in place 156 | | plugins = client.options.plugins 157 | | if any(isinstance(x, _MyPlugin) for x in plugins): 158 | | return 159 | | plugins.insert(0, _MyPlugin()) 160 | | client.set_options(plugins=plugins) 161 | """ 162 | def __init__(self): 163 | self._cache = ConnectionCache(no_current_msg='No current client') 164 | self._imports = [] 165 | self._logger = logger 166 | self._global_timeout = True 167 | self._external_options = weakref.WeakKeyDictionary() 168 | try: # exception if Robot is not running 169 | BuiltIn().set_global_variable("${SUDS_NULL}", null()) 170 | except: 171 | pass 172 | -------------------------------------------------------------------------------- /ExemploSOAPTesting/MyCustomSudsLibrary/options.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Kevin Ormbrek 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | 15 | from suds.xsd.doctor import Import 16 | from suds.xsd.sxbasic import Import as BasicImport 17 | from suds import ServiceNotFound 18 | from suds.transport.https import HttpAuthenticated 19 | from suds.transport.https import WindowsHttpAuthenticated 20 | from suds.transport.http import HttpAuthenticated as AlwaysSendTransport 21 | from .utils import * 22 | import robot 23 | 24 | 25 | class _OptionsKeywords(object): 26 | 27 | def set_service(self, service): 28 | """Sets the `service` to use in future requests. 29 | 30 | `service` should be the name or the index of the service as it appears in the WSDL. 31 | """ 32 | service = parse_index(service) 33 | self._client().set_options(service=service) 34 | 35 | def set_port(self, port): 36 | """Sets the `port` to use in future requests. 37 | 38 | `port` should be the name or the index of the port as it appears in the WSDL. 39 | """ 40 | port = parse_index(port) 41 | self._client().set_options(port=port) 42 | 43 | def set_proxies(self, *protocol_url_pairs): 44 | """Sets the http proxy settings. 45 | 46 | | Set Proxy | http | localhost:5000 | https | 10.0.4.23:80 | 47 | """ 48 | if len(protocol_url_pairs) % 2 != 0: 49 | raise ValueError("There should be an even number of protocol-url pairs.") 50 | proxy = {} 51 | for i in range(0, len(protocol_url_pairs), 2): 52 | proxy[protocol_url_pairs[i]] = protocol_url_pairs[i + 1] 53 | self._client().set_options(proxy=proxy) 54 | 55 | def set_headers(self, *dict_or_key_value_pairs): 56 | """Sets _extra_ http headers to send in future requests. 57 | 58 | For HTTP headers; not to be confused with the SOAP header element. 59 | 60 | Example: 61 | | Set Headers | X-Requested-With | autogen | # using key-value pairs | 62 | or using a dictionary: 63 | | ${headers}= | Create Dictionary | X-Requested-With | autogen | 64 | | Set Headers | ${headers} | | # using a dictionary | 65 | """ 66 | length = len(dict_or_key_value_pairs) 67 | if length == 1: 68 | headers = dict_or_key_value_pairs[0] 69 | elif length % 2 == 0: 70 | headers = {} 71 | for i in range(0, len(dict_or_key_value_pairs), 2): 72 | headers[dict_or_key_value_pairs[i]] = dict_or_key_value_pairs[i + 1] 73 | else: 74 | raise ValueError("There should be an even number of name-value pairs.") 75 | self._client().set_options(headers=headers) 76 | 77 | def set_soap_headers(self, *headers): 78 | """Sets SOAP headers to send in future requests. 79 | 80 | Example: 81 | | ${auth header}= | Create Wsdl Object | AuthHeader | | 82 | | Set Wsdl Object Attribute | ${auth header} | UserID | gcarlson | 83 | | Set Wsdl Object Attribute | ${auth header} | Password | heyOh | 84 | | Set Soap Headers | ${auth header} | # using WSDL object | | 85 | or using a dictionary: 86 | | ${auth dict}= | Create Dictionary | UserName | gcarlson | Password | heyOh | 87 | | Set Soap Headers | ${auth dict} | # using a dictionary | | | | 88 | 89 | For setting WS-Security elements in the SOAP header, see 90 | `Apply Username Token` and `Apply Security Timestamp`. 91 | """ 92 | self._client().set_options(soapheaders=headers) 93 | 94 | def set_return_xml(self, return_xml): 95 | """Sets whether to return XML in future requests. 96 | 97 | The default value is _False_. If `return_xml` is _True_, then return 98 | the SOAP envelope as a string in future requests. Otherwise, return a 99 | Python object graph. `Get Last Received` returns the XML received 100 | regardless of this setting. 101 | 102 | See also `Call Soap Method`, `Call Soap Method Expecting Fault`, and 103 | `Specific Soap Call`. 104 | 105 | Example: 106 | | ${old value}= | Set Return Xml | True | 107 | """ 108 | return_xml = to_bool(return_xml) 109 | # not using the retxml option built into Suds because Suds does not raise exceptions when a SOAP fault occurs 110 | # when retxml=True. Instead just use the XML that is already being captured with a plugin 111 | old_value = self._get_external_option("return_xml", False) 112 | self._set_external_option("return_xml", return_xml) 113 | return old_value 114 | 115 | def set_http_authentication(self, username, password, type='STANDARD'): 116 | """Sets http authentication type and credentials. 117 | 118 | Available types are STANDARD, ALWAYS_SEND, and NTLM. Type STANDARD 119 | will only send credentials to the server upon request (HTTP/1.0 401 120 | Authorization Required) by the server only. Type ALWAYS_SEND will 121 | cause an Authorization header to be sent in every request. Type NTLM 122 | is a Microsoft proprietary authentication scheme that requires the 123 | python-ntlm package to be installed, which is not packaged with Suds 124 | or SudsLibrary. 125 | """ 126 | transport = self._get_transport(type, username=username, password=password) 127 | self._client().set_options(transport=transport) 128 | 129 | def set_location(self, url, service=None, names=None): 130 | """Sets location to use in future requests. 131 | 132 | This is for when the location(s) specified in the WSDL are not correct. 133 | `service` is the name or index of the service to change and ignored 134 | unless there is more than one service. `names` should be either a 135 | comma-delimited list of methods names or an iterable (e.g. a list). If 136 | no methods names are given, then sets the location for all methods of 137 | the service(s). 138 | 139 | Example: 140 | | Set Location | http://localhost:8080/myWS | 141 | """ 142 | wsdl = self._client().wsdl 143 | service_count = len(wsdl.services) 144 | if (service_count == 1): 145 | service = 0 146 | elif not service is None: 147 | service = parse_index(service) 148 | if isinstance(names, bytes): 149 | names = names.split(b",") 150 | if service is None: 151 | for svc in wsdl.services: 152 | svc.setlocation(url, names) 153 | elif isinstance(service, int): 154 | wsdl.services[service].setlocation(url, names) 155 | else: 156 | for svc in wsdl.services: 157 | if svc.name == service: 158 | svc.setlocation(url, names) 159 | return 160 | raise ServiceNotFound(service) 161 | 162 | def add_doctor_import(self, import_namespace, location=None, filters=None): 163 | """Adds an import be used in the next client. 164 | 165 | Doctor imports are applied to the _next_ client created with 166 | `Create Soap Client`. Doctor imports are necessary when references are 167 | made in one schema to named objects defined in another schema without 168 | importing it. Use `location` to specify the location to download the 169 | schema file. `filters` should be either a comma-delimited list of 170 | namespaces or an iterable (e.g. a list). 171 | 172 | The following example would import the SOAP encoding schema into only 173 | the namespace http://some/namespace/A if it is not already imported: 174 | | Add Doctor Import | http://schemas.xmlsoap.org/soap/encoding/ | filters=http://some/namespace/A | 175 | """ 176 | if isinstance(filters, bytes): 177 | filters = filters.split(b",") 178 | imp = Import(import_namespace, location) 179 | if not filters is None: 180 | for filter in filters: 181 | imp.filter.add(filter) 182 | self._imports.append(imp) 183 | 184 | def bind_schema_to_location(self, namespace, location): 185 | """Sets the `location` for the given `namespace` of a schema. 186 | 187 | This is for when an import statement specifies a schema but not its 188 | location. If the schemaLocation is present and incorrect, this will 189 | not override that. Bound schemas are shared amongst all instances of 190 | SudsLibrary. Schemas should be bound if necessary before `Add Doctor 191 | Import` or `Create Soap Client` where appropriate. 192 | """ 193 | BasicImport.bind(namespace, location) 194 | 195 | def set_soap_timeout(self, timeout): 196 | """Sets the timeout for SOAP requests. 197 | 198 | `timeout` must be given in Robot Framework's time format (e.g. 199 | '1 minute', '2 min 3 s', '4.5'). The default timeout is 90 seconds. 200 | 201 | Example: 202 | | Set Soap Timeout | 3 min | 203 | """ 204 | self._set_soap_timeout(timeout) 205 | timestr = format_robot_time(timeout) 206 | self._logger.info("SOAP timeout set to %s" % timestr) 207 | 208 | # private 209 | 210 | def _set_boolean_option(self, name, value): 211 | value = to_bool(value) 212 | self._client().set_options(**{name: value}) 213 | 214 | def _set_soap_timeout(self, timeout): 215 | timeout_in_secs = robot.utils.timestr_to_secs(timeout) 216 | self._client().set_options(timeout=timeout_in_secs) 217 | 218 | def _get_external_option(self, name, default): 219 | value = default 220 | if self._client() in self._external_options: 221 | options = self._external_options[self._client()] 222 | value = options.get(name, default) 223 | return value 224 | 225 | def _set_external_option(self, name, value): 226 | if self._client() not in self._external_options: 227 | self._external_options[self._client()] = {} 228 | old_value = self._external_options[self._client()].get(name, None) 229 | self._external_options[self._client()][name] = value 230 | return old_value 231 | 232 | def _get_transport(self, auth_type, username, password): 233 | classes = { 234 | 'STANDARD': HttpAuthenticated, 235 | 'ALWAYS_SEND': AlwaysSendTransport, 236 | 'NTLM': WindowsHttpAuthenticated 237 | } 238 | try: 239 | _class = classes[auth_type.upper().strip()] 240 | except KeyError: 241 | raise ValueError("'%s' is not a supported authentication type." % auth_type) 242 | transport = _class(username=username, password=password) 243 | return transport 244 | -------------------------------------------------------------------------------- /Exemplo Imap Library/CustomImapLibrary.py: -------------------------------------------------------------------------------- 1 | """ 2 | IMAP Library - a IMAP email testing library. 3 | """ 4 | import base64 5 | from email import message_from_string 6 | from imaplib import IMAP4, IMAP4_SSL 7 | from re import findall 8 | from time import sleep, time 9 | try: 10 | from urllib.request import urlopen 11 | except ImportError: 12 | from urllib2 import urlopen 13 | from builtins import str 14 | 15 | 16 | class CustomImapLibrary(object): 17 | 18 | PORT = 143 19 | PORT_SECURE = 993 20 | FOLDER = 'INBOX' 21 | ROBOT_LIBRARY_SCOPE = 'GLOBAL' 22 | 23 | def __init__(self): 24 | """ImapLibrary can be imported without argument. 25 | 26 | Examples: 27 | | = Keyword Definition = | = Description = | 28 | | Library `|` ImapLibrary | Initiate Imap library | 29 | """ 30 | self._email_index = None 31 | self._imap = None 32 | self._mails = [] 33 | self._mp_iter = None 34 | self._mp_msg = None 35 | self._part = None 36 | 37 | def close_mailbox(self): 38 | """Close IMAP email client session. 39 | 40 | Examples: 41 | | Close Mailbox | 42 | """ 43 | self._imap.close() 44 | 45 | def delete_all_emails(self): 46 | """Delete all emails. 47 | 48 | Examples: 49 | | Delete All Emails | 50 | """ 51 | typ, mails = self._imap.uid('search', None, 'ALL') 52 | self._mails = mails[0].split() 53 | 54 | print("Deleting e-mails from ID: [{0}]".format(', '.join(map(str, self._mails)))) 55 | 56 | for mail in self._mails: 57 | self.delete_email(mail) 58 | self._imap.expunge() 59 | 60 | def decode_email_body(self, body_email_encoded): 61 | """Returns the email body encoded on base64 decoded to a string UTF-8. 62 | 63 | Arguments: 64 | - ``body_email_encoded``: An string from the email body encoded on base64. 65 | 66 | Examples: 67 | | BODY | Get Email Body | EMAIL_INDEX | 68 | | BODYDECODED | Decode Email Body | BODY | 69 | | Log | BODY | 70 | """ 71 | print("Deconding [%s] to string." % (body_email_encoded)) 72 | 73 | if not body_email_encoded.endswith("=="): 74 | body_email_encoded = body_email_encoded + "==" 75 | 76 | email_decoded = base64.b64decode(body_email_encoded) 77 | 78 | return email_decoded.decode('UTF-8') 79 | 80 | def delete_all_emails_with_kwargs(self, **kwargs): 81 | """Delete all emails. 82 | 83 | Examples: 84 | | Delete All Emails | 85 | """ 86 | self._mails = self._check_emails(**kwargs) 87 | 88 | for mail in self._mails: 89 | self.delete_email(mail) 90 | self._imap.expunge() 91 | 92 | def delete_email(self, email_index): 93 | """Delete email on given ``email_index``. 94 | 95 | Arguments: 96 | - ``email_index``: An email index to identity the email message. 97 | 98 | Examples: 99 | | Delete Email | INDEX | 100 | """ 101 | self._imap.uid('store', email_index, '+FLAGS', r'(\DELETED)') 102 | self._imap.expunge() 103 | 104 | def get_email_body(self, email_index): 105 | """Returns the decoded email body on multipart email message, 106 | otherwise returns the body text. 107 | 108 | Arguments: 109 | - ``email_index``: An email index to identity the email message. 110 | 111 | Examples: 112 | | Get Email Body | INDEX | 113 | """ 114 | if self._is_walking_multipart(email_index): 115 | body = self.get_multipart_payload(decode=True) 116 | else: 117 | body = self._imap.uid('fetch', 118 | email_index, 119 | '(BODY[TEXT])')[1][0][1].\ 120 | decode('quoted-printable') 121 | return body 122 | 123 | def get_links_from_email(self, email_index): 124 | """Returns all links found in the email body from given ``email_index``. 125 | 126 | Arguments: 127 | - ``email_index``: An email index to identity the email message. 128 | 129 | Examples: 130 | | Get Links From Email | INDEX | 131 | """ 132 | body = self.get_email_body(email_index) 133 | return findall(r'href=[\'"]?([^\'" >]+)', body) 134 | 135 | def get_matches_from_email(self, email_index, pattern): 136 | """Returns all Regular Expression ``pattern`` found in the email body 137 | from given ``email_index``. 138 | 139 | Arguments: 140 | - ``email_index``: An email index to identity the email message. 141 | - ``pattern``: It consists of one or more character literals, operators, or constructs. 142 | 143 | Examples: 144 | | Get Matches From Email | INDEX | PATTERN | 145 | """ 146 | body = self.get_email_body(email_index) 147 | return findall(pattern, body) 148 | 149 | def get_multipart_content_type(self): 150 | """Returns the content type of current part of selected multipart email message. 151 | 152 | Examples: 153 | | Get Multipart Content Type | 154 | """ 155 | return self._part.get_content_type() 156 | 157 | def get_multipart_field(self, field): 158 | """Returns the value of given header ``field`` name. 159 | 160 | Arguments: 161 | - ``field``: A header field name: ``From``, ``To``, ``Subject``, ``Date``, etc. 162 | All available header field names of an email message can be found by running 163 | `Get Multipart Field Names` keyword. 164 | 165 | Examples: 166 | | Get Multipart Field | Subject | 167 | """ 168 | return self._mp_msg[field] 169 | 170 | def get_multipart_field_names(self): 171 | """Returns all available header field names of selected multipart email message. 172 | 173 | Examples: 174 | | Get Multipart Field Names | 175 | """ 176 | return list(self._mp_msg.keys()) 177 | 178 | def get_multipart_payload(self, decode=False): 179 | """Returns the payload of current part of selected multipart email message. 180 | 181 | Arguments: 182 | - ``decode``: An indicator flag to decode the email message. (Default False) 183 | 184 | Examples: 185 | | Get Multipart Payload | 186 | | Get Multipart Payload | decode=True | 187 | """ 188 | payload = self._part.get_payload(decode=decode) 189 | charset = self._part.get_content_charset() 190 | if charset is not None: 191 | return payload.decode(charset) 192 | return payload 193 | 194 | def mark_all_emails_as_read(self): 195 | """Mark all received emails as read. 196 | 197 | Examples: 198 | | Mark All Emails As Read | 199 | """ 200 | for mail in self._mails: 201 | self._imap.uid('store', mail, '+FLAGS', r'\SEEN') 202 | 203 | def mark_as_read(self): 204 | """****DEPRECATED**** 205 | Shortcut to `Mark All Emails As Read`. 206 | """ 207 | self.mark_all_emails_as_read() 208 | 209 | def mark_email_as_read(self, email_index): 210 | """Mark email on given ``email_index`` as read. 211 | 212 | Arguments: 213 | - ``email_index``: An email index to identity the email message. 214 | 215 | Examples: 216 | | Mark Email As Read | INDEX | 217 | """ 218 | self._imap.uid('store', email_index, '+FLAGS', r'\SEEN') 219 | 220 | def open_link_from_email(self, email_index, link_index=0): 221 | """Open link URL from given ``link_index`` in email message body of given ``email_index``. 222 | Returns HTML content of opened link URL. 223 | 224 | Arguments: 225 | - ``email_index``: An email index to identity the email message. 226 | - ``link_index``: The link index to be open. (Default 0) 227 | 228 | Examples: 229 | | Open Link From Email | 230 | | Open Link From Email | 1 | 231 | """ 232 | urls = self.get_links_from_email(email_index) 233 | 234 | if len(urls) > link_index: 235 | resp = urlopen(urls[link_index]) 236 | content_type = resp.headers.getheader('content-type') 237 | if content_type: 238 | enc = content_type.split('charset=')[-1] 239 | return str(resp.read(), enc) 240 | else: 241 | return resp.read() 242 | else: 243 | raise AssertionError("Link number %i not found!" % link_index) 244 | 245 | def open_link_from_mail(self, email_index, link_index=0): 246 | """****DEPRECATED**** 247 | Shortcut to `Open Link From Email`. 248 | """ 249 | return self.open_link_from_email(email_index, link_index) 250 | 251 | def open_mailbox(self, **kwargs): 252 | """Open IMAP email client session to given ``host`` with given ``user`` and ``password``. 253 | 254 | Arguments: 255 | - ``host``: The IMAP host server. (Default None) 256 | - ``is_secure``: An indicator flag to connect to IMAP host securely or not. (Default True) 257 | - ``password``: The plaintext password to be use to authenticate mailbox on given ``host``. 258 | - ``port``: The IMAP port number. (Default None) 259 | - ``user``: The username to be use to authenticate mailbox on given ``host``. 260 | - ``folder``: The email folder to read from. (Default INBOX) 261 | 262 | Examples: 263 | | Open Mailbox | host=HOST | user=USER | password=SECRET | 264 | | Open Mailbox | host=HOST | user=USER | password=SECRET | is_secure=False | 265 | | Open Mailbox | host=HOST | user=USER | password=SECRET | port=8000 | 266 | | Open Mailbox | host=HOST | user=USER | password=SECRET | folder=Drafts 267 | """ 268 | host = kwargs.pop('host', kwargs.pop('server', None)) 269 | is_secure = kwargs.pop('is_secure', 'True') == 'True' 270 | port = int(kwargs.pop('port', self.PORT_SECURE if is_secure else self.PORT)) 271 | folder = '"%s"' % str(kwargs.pop('folder', self.FOLDER)) 272 | self._imap = IMAP4_SSL(host, port) if is_secure else IMAP4(host, port) 273 | self._imap.login(kwargs.pop('user', None), kwargs.pop('password', None)) 274 | self._imap.select(folder) 275 | self._init_multipart_walk() 276 | 277 | def wait_for_email(self, **kwargs): 278 | """Wait for email message to arrived base on any given filter criteria. 279 | Returns email index of the latest email message received. 280 | 281 | Arguments: 282 | - ``poll_frequency``: The delay value in seconds to retry the mailbox check. (Default 10) 283 | - ``recipient``: Email recipient. (Default None) 284 | - ``sender``: Email sender. (Default None) 285 | - ``status``: A mailbox status filter: ``MESSAGES``, ``RECENT``, ``UIDNEXT``, 286 | ``UIDVALIDITY``, and ``UNSEEN``. 287 | Please see [https://goo.gl/3KKHoY|Mailbox Status] for more information. 288 | (Default None) 289 | - ``subject``: Email subject. (Default None) 290 | - ``text``: Email body text. (Default None) 291 | - ``timeout``: The maximum value in seconds to wait for email message to arrived. 292 | (Default 60) 293 | - ``folder``: The email folder to check for emails. (Default INBOX) 294 | 295 | Examples: 296 | | Wait For Email | sender=noreply@domain.com | 297 | | Wait For Email | sender=noreply@domain.com | folder=OUTBOX 298 | """ 299 | poll_frequency = float(kwargs.pop('poll_frequency', 10)) 300 | timeout = int(kwargs.pop('timeout', 60)) 301 | end_time = time() + timeout 302 | while time() < end_time: 303 | self._mails = self._check_emails(**kwargs) 304 | if len(self._mails) > 0: 305 | return self._mails[-1] 306 | if time() < end_time: 307 | sleep(poll_frequency) 308 | raise AssertionError("No email received within %ss" % timeout) 309 | 310 | def wait_for_mail(self, **kwargs): 311 | """****DEPRECATED**** 312 | Shortcut to `Wait For Email`. 313 | """ 314 | return self.wait_for_email(**kwargs) 315 | 316 | def walk_multipart_email(self, email_index): 317 | """Returns total parts of a multipart email message on given ``email_index``. 318 | Email message is cache internally to be used by other multipart keywords: 319 | `Get Multipart Content Type`, `Get Multipart Field`, `Get Multipart Field Names`, 320 | `Get Multipart Field`, and `Get Multipart Payload`. 321 | 322 | Arguments: 323 | - ``email_index``: An email index to identity the email message. 324 | 325 | Examples: 326 | | Walk Multipart Email | INDEX | 327 | """ 328 | if not self._is_walking_multipart(email_index): 329 | data = self._imap.uid('fetch', email_index, '(RFC822)')[1][0][1] 330 | msg = message_from_string(data) 331 | self._start_multipart_walk(email_index, msg) 332 | try: 333 | self._part = next(self._mp_iter) 334 | except StopIteration: 335 | self._init_multipart_walk() 336 | return False 337 | # return number of parts 338 | return len(self._mp_msg.get_payload()) 339 | 340 | def _check_emails(self, **kwargs): 341 | """Returns filtered email.""" 342 | folder = '"%s"' % str(kwargs.pop('folder', self.FOLDER)) 343 | criteria = self._criteria(**kwargs) 344 | # Calling select before each search is necessary with gmail 345 | status, data = self._imap.select(folder) 346 | if status != 'OK': 347 | raise Exception("imap.select error: %s, %s" % (status, data)) 348 | typ, msgnums = self._imap.uid('search', None, *criteria) 349 | if typ != 'OK': 350 | raise Exception('imap.search error: %s, %s, criteria=%s' % (typ, msgnums, criteria)) 351 | return msgnums[0].split() 352 | 353 | @staticmethod 354 | def _criteria(**kwargs): 355 | """Returns email criteria.""" 356 | criteria = [] 357 | recipient = kwargs.pop('recipient', kwargs.pop('to_email', kwargs.pop('toEmail', None))) 358 | sender = kwargs.pop('sender', kwargs.pop('from_email', kwargs.pop('fromEmail', None))) 359 | status = kwargs.pop('status', None) 360 | subject = kwargs.pop('subject', None) 361 | text = kwargs.pop('text', None) 362 | if recipient: 363 | criteria += ['TO', '"%s"' % recipient] 364 | if sender: 365 | criteria += ['FROM', '"%s"' % sender] 366 | if subject: 367 | criteria += ['SUBJECT', '"%s"' % subject] 368 | if text: 369 | criteria += ['TEXT', '"%s"' % text] 370 | if status: 371 | criteria += [status] 372 | if not criteria: 373 | criteria = ['UNSEEN'] 374 | return criteria 375 | 376 | def _init_multipart_walk(self): 377 | """Initialize multipart email walk.""" 378 | self._email_index = None 379 | self._mp_msg = None 380 | self._part = None 381 | 382 | def _is_walking_multipart(self, email_index): 383 | """Returns boolean value whether the multipart email walk is in-progress or not.""" 384 | return self._mp_msg is not None and self._email_index == email_index 385 | 386 | def _start_multipart_walk(self, email_index, msg): 387 | """Start multipart email walk.""" 388 | self._email_index = email_index 389 | self._mp_msg = msg 390 | self._mp_iter = msg.walk() 391 | -------------------------------------------------------------------------------- /RabbitMQ/RabbitMqCustom.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | from robot.api import logger 4 | from robot.utils import ConnectionCache 5 | import http.client 6 | import base64 7 | import json 8 | import socket 9 | import urllib.parse 10 | import urllib 11 | 12 | 13 | class RabbitMqCustom(object): 14 | """ 15 | Library for managing the server RabbitMq. 16 | 17 | == Example == 18 | | *Settings* | *Value* | 19 | | Library | RabbitMqManager | 20 | | Library | Collections | 21 | 22 | | *Test Cases* | *Action* | *Argument* | *Argument* | *Argument* | *Argument* | *Argument* | 23 | | Simple | 24 | | | Connect To Rabbitmq | my_host_name | 15672 | guest | guest | alias=rmq | 25 | | | ${overview}= | Overview | 26 | | | Log Dictionary | ${overview} | 27 | | | Close All Rabbitmq Connections | 28 | """ 29 | 30 | ROBOT_LIBRARY_SCOPE = 'GLOBAL' 31 | 32 | def __init__(self): 33 | self._connection = None 34 | self.headers = None 35 | self._cache = ConnectionCache() 36 | 37 | def connect_to_rabbitmq(self, host, port, username='guest', password='guest', timeout=15, alias=None): 38 | """ 39 | Connecting to the server RabbitMq. 40 | 41 | *Args:*\n 42 | _host_ - server name;\n 43 | _port_ - port number;\n 44 | _username_ - is the name of the user;\n 45 | _password_ - is the user password;\n 46 | _timeout_ - connection timeout;\n 47 | _alias_ - connection alias;\n 48 | 49 | *Returns:*\n 50 | The index of the current connection. 51 | 52 | *Raises:*\n 53 | socket.error if you can not create a connection. 54 | 55 | *Example:*\n 56 | | Connect To Rabbitmq | my_host_name | 15672 | guest | guest | alias=rmq | 57 | """ 58 | 59 | port = int(port) 60 | timeout = int(timeout) 61 | logger.debug('Connecting using : host=%s, port=%d, username=%s, password=%s, timeout=%d, alias=%s ' % ( 62 | host, port, username, password, timeout, alias)) 63 | self.headers = {"Authorization": b"Basic " + 64 | base64.b64encode(username.encode() + b":" + password.encode())} 65 | logger.debug(self.headers) 66 | try: 67 | self._connection = http.client.HTTPConnection(host, port, timeout) 68 | self._connection.connect() 69 | return self._cache.register(self._connection, alias) 70 | except socket.error as e: 71 | raise Exception("Could not connect to RabbitMq", str(e)) 72 | 73 | def switch_rabbitmq_connection(self, index_or_alias): 74 | """ 75 | Switch between active connections with RabbitMq, using their index or alias.. 76 | 77 | The alias is specified in the keyword [#Connect To Rabbitmq|Connect To Rabbitmq], which also returns the connection index. 78 | 79 | *Args:*\n 80 | _index_or_alias_ - index of a connection or its alias; 81 | 82 | *Returns:*\n 83 | Index of the previous connection.. 84 | 85 | *Example:*\n 86 | | Connect To Rabbitmq | my_host_name_1 | 15672 | guest | guest | alias=rmq1 | 87 | | Connect To Rabbitmq | my_host_name_2 | 15672 | guest | guest | alias=rmq2 | 88 | | Switch Rabbitmq Connection | rmq1 | 89 | | ${live}= | Is alive | 90 | | Switch Rabbitmq Connection | rmq2 | 91 | | ${live}= | Is alive | 92 | | Close All Rabbitmq Connections | 93 | """ 94 | 95 | old_index = self._cache.current_index 96 | self._connection = self._cache.switch(index_or_alias) 97 | return old_index 98 | 99 | def disconnect_from_rabbitmq(self): 100 | """ 101 | Closing the current connection to RabbitMq. 102 | 103 | *Example:*\n 104 | | Connect To Rabbitmq | my_host_name | 15672 | guest | guest | alias=rmq | 105 | | Disconnect From Rabbitmq | 106 | """ 107 | 108 | logger.debug('Close connection with : host=%s, port=%d ' % 109 | (self._connection.host, self._connection.port)) 110 | self._connection.close() 111 | 112 | def close_all_rabbitmq_connections(self): 113 | """ 114 | Closing all connections from RabbitMq.. 115 | 116 | This keyword is used to close all connections in the event that several of them were opened. 117 | Use [#Disconnect From Rabbitmq|Disconnect From Rabbitmq] и [#Close All Rabbitmq Connections|Close All Rabbitmq Connections] 118 | together it is impossible.. 119 | 120 | After this keyword is executed, the index returned by [#Connect To Rabbitmq|Connect To Rabbitmq], starts at 1. 121 | 122 | *Example:*\n 123 | | Connect To Rabbitmq | my_host_name | 15672 | guest | guest | alias=rmq | 124 | | Close All Rabbitmq Connections | 125 | """ 126 | 127 | self._connection = self._cache.close_all() 128 | 129 | def _http_request(self, method, path, body): 130 | """ 131 | Querying for RabbitMq 132 | 133 | *Args:*\n 134 | _method_ - query method;\n 135 | _path_ - uri request;\n 136 | _body_ - body POST request;\n 137 | """ 138 | 139 | if body != "": 140 | self.headers["Content-Type"] = "application/json" 141 | 142 | logger.debug('Prepared request with method ' + method + ' to ' + 'http://' + 143 | self._connection.host + ':' + str(self._connection.port) + path + ' and body\n' + body) 144 | 145 | try: 146 | # TODO: analiser o funcionamento do cache de conexão 147 | # precisa recriar a toda hora? 148 | self._connection = http.client.HTTPConnection( 149 | self._connection.host, self._connection.port, 150 | self._connection.timeout) 151 | self._connection.connect() 152 | 153 | self._connection.request(method, path, body, self.headers) 154 | except socket.error as e: 155 | raise Exception("Could not send request: {0}".format(e)) 156 | 157 | resp = self._connection.getresponse() 158 | s = resp.read() 159 | 160 | if resp.status == 400: 161 | raise Exception(json.loads(s)) 162 | if resp.status == 401: 163 | raise Exception("Access refused: {0}".format( 164 | 'http://' + self._connection.host + ':' + str(self._connection.port) + path)) 165 | if resp.status == 404: 166 | raise Exception("Not found: {0}".format( 167 | 'http://' + self._connection.host + ':' + str(self._connection.port) + path)) 168 | if resp.status == 301: 169 | url = urllib.parse.urlparse(resp.getheader('location')) 170 | raise Exception(url) 171 | [host, port] = url.netloc.split(':') 172 | self.options.hostname = host 173 | self.options.port = int(port) 174 | return self.http(method, url.path + '?' + url.query, body) 175 | if resp.status < 200 or resp.status > 400: 176 | raise Exception("Received %d %s for request %s\n%s" 177 | % (resp.status, resp.reason, 'http://' + self._connection.host + ':' + str(self._connection.port) + path, resp.read())) 178 | return s 179 | 180 | def _get(self, path): 181 | return self._http_request('GET', '/api%s' % path, '') 182 | 183 | def _put(self, path, body): 184 | print("/api%s" % path) 185 | return self._http_request("PUT", "/api%s" % path, body) 186 | 187 | def _post(self, path, body): 188 | return self._http_request("POST", "/api%s" % path, body) 189 | 190 | def _delete(self, path): 191 | return self._http_request("DELETE", "/api%s" % path, "") 192 | 193 | def _quote_vhost(self, vhost): 194 | """ 195 | Decodificação vhost. 196 | """ 197 | 198 | if vhost == '/': 199 | vhost = '%2F' 200 | if vhost != '%2F': 201 | vhost = urllib.parse.quote(vhost) 202 | return vhost 203 | 204 | def is_alive(self): 205 | """ 206 | RabbitMq health check.. 207 | 208 | The GET request is sent as follows: 'http://:/api/' and the return code is checked. 209 | 210 | *Returns:*\n 211 | bool True, if the return code is 200.\n 212 | bool False in all other cases. 213 | 214 | *Raises:*\n 215 | socket.error in case it is unreasonable to send a GET request. 216 | 217 | *Example:*\n 218 | | ${live}= | Is Alive | 219 | =>\n 220 | True 221 | """ 222 | 223 | try: 224 | self._get('/cluster-name') 225 | except Exception: 226 | return False 227 | 228 | return True 229 | 230 | def overview(self): 231 | """ 232 | Information about the server RabbitMq. 233 | 234 | *Returns:*\n 235 | Dictionary with information about the server. 236 | 237 | *Example:*\n 238 | | ${overview}= | Overview | 239 | | Log Dictionary | ${overview} | 240 | | ${version}= | Get From Dictionary | ${overview} | rabbitmq_version | 241 | =>\n 242 | Dictionary size is 13 and it contains following items: 243 | | erlang_full_version | Erlang R16B02 (erts-5.10.3) [source] [64-bit] [smp:2:2] [async-threads:30] [hipe] [kernel-poll:true] | 244 | | erlang_version | R16B02 | 245 | | listeners | [{u'node': u'rabbit@srv2-rs582b-m', u'ip_address': u'0.0.0.0', u'protocol': u'amqp', u'port': 5672}] | 246 | | management_version | 3.6.6 | 247 | | message_stats | [] | 248 | 249 | ${version} = 3.6.6 250 | """ 251 | 252 | return json.loads(self._get('/overview')) 253 | 254 | def connections(self): 255 | """ 256 | A list of open connections.. 257 | """ 258 | 259 | return json.loads(self._get('/connections')) 260 | 261 | def get_name_of_all_connections(self): 262 | """ 263 | A list of the names of all open connections. 264 | """ 265 | 266 | names = [] 267 | data = self.connections() 268 | for item in data: 269 | names.append(item['name']) 270 | return names 271 | 272 | def channels(self): 273 | """ 274 | List of open channels. 275 | """ 276 | 277 | return json.loads(self._get('/channels')) 278 | 279 | def exchanges(self): 280 | """ 281 | Exchange list. 282 | 283 | *Example:*\n 284 | | ${exchanges}= | Exchanges | 285 | | Log List | ${exchanges} | 286 | | ${item}= | Get From list | ${exchanges} | 1 | 287 | | ${name}= | Get From Dictionary | ${q} | name | 288 | =>\n 289 | List length is 8 and it contains following items: 290 | | 0 | {u'name': u'', u'durable': True, u'vhost': u'/', u'internal': False, u'message_stats': [], u'arguments': {}, u'type': u'direct', u'auto_delete': False} | 291 | | 1 | {u'name': u'amq.direct', u'durable': True, u'vhost': u'/', u'internal': False, u'message_stats': [], u'arguments': {}, u'type': u'direct', u'auto_delete': False} | 292 | ...\n 293 | ${name} = amq.direct 294 | """ 295 | 296 | return json.loads(self._get('/exchanges')) 297 | 298 | def get_names_of_all_exchanges(self): 299 | """ 300 | List of names of all exchanges. 301 | 302 | *Example:*\n 303 | | ${names}= | Get Names Of All Exchanges | 304 | | Log List | ${names} | 305 | =>\n 306 | | List has one item: 307 | | amq.direct 308 | """ 309 | 310 | names = [] 311 | data = self.exchanges() 312 | for item in data: 313 | names.append(item['name']) 314 | return names 315 | 316 | def queues(self): 317 | """ 318 | List of queues. 319 | """ 320 | 321 | return json.loads(self._get('/queues')) 322 | 323 | def get_queues_on_vhost(self, vhost='%2F'): 324 | """ 325 | List of queues for the virtual host. 326 | 327 | *Args:*\n 328 | _vhost_ -the name of the virtual host (recoded using urllib.parse.quote) 329 | """ 330 | 331 | return json.loads(self._get('/queues/' + self._quote_vhost(vhost))) 332 | 333 | def get_queue(self, name, vhost='%2F'): 334 | """ 335 | List of queues for the virtual host. 336 | 337 | *Args:*\n 338 | _queue_name_ - queue name;\n 339 | _vhost_ - the name of the virtual host (recoded using urllib.parse.quote) 340 | """ 341 | 342 | return json.loads(self._get('/queues/' + self._quote_vhost(vhost) + '/' + urllib.parse.quote(name))) 343 | 344 | def get_names_of_queues_on_vhost(self, vhost='%2F'): 345 | """ 346 | List of virtual host queue names. 347 | 348 | *Args:*\n 349 | - vhost: the name of the virtual host (recoded using urllib.parse.quote) 350 | 351 | *Example:*\n 352 | | ${names}= | Get Names Of Queues On Vhost | 353 | | Log List | ${names} | 354 | =>\n 355 | | List has one item: 356 | | federation: ex2 -> rabbit@server.br 357 | """ 358 | names = [] 359 | data = self.get_queues_on_vhost(vhost) 360 | for item in data: 361 | names.append(item['name']) 362 | return names 363 | 364 | def queue_exists(self, queue, vhost='%2F'): 365 | """ 366 | Verifies that the one or more queues exists 367 | """ 368 | names = self.get_names_of_queues_on_vhost() 369 | if queue in names: 370 | return True 371 | else: 372 | return False 373 | 374 | def delete_queues_by_name(self, name, vhost='%2F'): 375 | """ 376 | Remove the queue from the virtual host. 377 | 378 | *Args:*\n 379 | _name_ - is the name of the queue;\n 380 | _vhost_ - is the name of the virtual host;\n 381 | """ 382 | print('Deletando a fila: %s' % (name)) 383 | return self._delete('/queues/' + self._quote_vhost(vhost) + '/' + urllib.parse.quote(name)) 384 | 385 | def vhosts(self): 386 | """ 387 | List of virtual hosts. 388 | """ 389 | return json.loads(self._get('/vhosts')) 390 | 391 | def nodes(self): 392 | """ 393 | List of nodes in the RabbitMQ cluster 394 | """ 395 | return json.loads(self._get('/nodes')) 396 | 397 | @property 398 | def _cluster_name(self): 399 | """ 400 | Name identifying this RabbitMQ cluster. 401 | """ 402 | return json.loads(self._get('/cluster-name')) 403 | 404 | def create_queues_by_name(self, name, auto_delete=False, durable=True, arguments={}, vhost='%2F'): 405 | """ 406 | Create an individual queue. 407 | """ 408 | print('Criando a fila: %s' % (name)) 409 | node = self._cluster_name['name'] 410 | body = json.dumps({ 411 | "auto_delete": auto_delete, 412 | "durable": "true", 413 | "arguments": arguments, 414 | "node": node 415 | }) 416 | print("Body: %s" % body) 417 | print('/queues/' + self._quote_vhost(vhost) + '/' + urllib.parse.quote(name)) 418 | return self._put('/queues/' + self._quote_vhost(vhost) + '/' + urllib.parse.quote(name), body=body) 419 | 420 | def publish_message_by_name(self, queue, msg, properties, vhost='%2F'): 421 | """ 422 | Publish a message to a given exchange 423 | """ 424 | 425 | name = "amq.default" 426 | body = json.dumps({ 427 | "properties": properties, 428 | "routing_key": queue, 429 | "payload": msg, 430 | "payload_encoding": "string" 431 | }) 432 | routed = self._post('/exchanges/' + self._quote_vhost(vhost) + 433 | '/' + urllib.parse.quote(name) + '/publish', body=body) 434 | print("Body Enviado: %s" % body) 435 | print("Fila Publicada: %s" % queue) 436 | return json.loads(routed) 437 | 438 | def get_messages_by_queue(self, queue, count=5, requeue=False, encoding="auto", truncate=2000000, vhost='%2F'): 439 | """ 440 | Get messages from a queue. 441 | """ 442 | 443 | print('Pegando %s mensagens da fila: %s' % (count, queue)) 444 | body = json.dumps({ 445 | "count": 446 | count, 447 | "requeue": 448 | requeue, 449 | "encoding": 450 | encoding, 451 | "truncate": 452 | truncate, 453 | "ackmode": 454 | "ack_requeue_true" if requeue else "ack_requeue_false" 455 | }) 456 | messages = self._post('/queues/' + self._quote_vhost(vhost) + 457 | '/' + urllib.parse.quote(queue) + '/get', body=body) 458 | return json.loads(messages) 459 | 460 | def purge_messages_by_queue(self, name, vhost='%2F'): 461 | """ 462 | Purge contents of a queue. 463 | """ 464 | print('Apagando as mensagens da fila: %s' % (name)) 465 | return self._delete('/queues/' + self._quote_vhost(vhost) + '/' + urllib.parse.quote(name) + '/contents') 466 | --------------------------------------------------------------------------------