sexta-feira, 5 de junho de 2020

Main looper has queued unexecuted runnables

"Main looper has queued unexecuted runnables. This might be the cause of the test failure. You might need a shadowOf(getMainLooper()).idle() call."

Pensa em uma mensagem de erro que me deu problema!

Essa mensagem pode dar em testes automatizados no Android. Estou usando Android Studio, JUnit, e auxílio do Robolectric para os testes. Especificamente no meu caso, isso era um problema que acontecia nos meus testes em que abro um DatePicker (aquele negócio de selecionar uma data), coloco uma data e dou Ok. Depois que faço iss, na minha aplicação, acontece uma requisição para um site. Essa requisição, como resposta, coloca itens em uma lista.

E aí vinha o problema: ao verificar a lista, às vezes os itens estavam lá, às vezes não!

Quando eles não estavam lá, eu ganhava um erro e ele tinha essa mensagem acima. Tentei e desisti várias vezes de consertar isso. Já fiz testes rodarem de novo até passar, e ignorei o erro por algum tempo.

Então a última vez eu comecei a olhar mais a fundo. Segui a sugestão da mensagem, adicionar esse tal shadowOf(getMainLooper()).idle(). Mas ela não diz exatamente onde. E o pior do erro intermitente: tem que rodar várias vezes, porque às vezes o teste funciona, mas o problema está lá ainda. Determinei que rodaria 20 vezes, se desse certo... E falhou. Acho que na 3ª tentativa.

Fui colocando o shadowOf(getMainLooper()).idle() mais para baixo no teste. Teve vez que deu erro até na 7ª, 10ª vez! Então me deu um estralo e fui ver qual era a explicação da função idle (shadowOf(getMainLooper()).idle()): "Executes all posted tasks scheduled before or at the current time". Traduzindo: "Executa todas as tarefas agendadas antes e no momento atual".

Testes intermitentes podem acontecer porque algo que foi chamado não terminou de executar. Essa função faz com que seu teste espere certas coisas terminarem. Por isso o android sugere que você use ela.

No meu caso, o lugar certo de executar ela foi logo antes de verificar se os dados da lista que eu estava preenchendo.

O código no momento que escrevo está em uma branch no github. O primeiro link é da branch:
https://github.com/darakeon/dfm/blob/4.1.4.5/android/DFM/src/test/kotlin/com/darakeon/dfm/summary/SummaryActivityTest.kt#L234

Caso ele não funcione mais, quer dizer que já coloquei em produção, tente ver no segundo link. Procure por um teste chamado dateDialog:
https://github.com/darakeon/dfm/blob/master/android/DFM/src/test/kotlin/com/darakeon/dfm/summary/SummaryActivityTest.kt

sexta-feira, 23 de junho de 2017

Certificado Inválido no Firefox

Criei um programa que adiciona certificados ao Firefox, para possibilitar fazer comunicação via websocket com sites HTTPS. Sem o certificado, os browsers não reconhecem o site porque não podem enviar uma requisição de uma conexão encriptada para uma não encriptada.

Para fazer isso, gero dois certificados:
- um deles é o root, auto-assinado;
- o segundo é de fato usado na conexão, é assinado pelo primeiro.

No caso de Chrome e IE, o certificado é adicionado na Store do Windows. Nela, adiciona-se o certificado CA na Root Store e o SSL na My. No caso do Firefox, tem uma Store própria. Para adicionar o certificado, eu estava usando isso:

certutil.exe -d [cert8.db path] -A -t "TCu,Cuw,Tuw" -n [name] -i [crt path]
-d: diretório do firefox
-A: comando de adicionar

Um dia fui rodar e descobri que não funcionava mais no Firefox. Na hora de adicionar, não reportava erro. Usando a opção -L, o certificado era listado como adicionado. Mesmo olhando em Tools > Options > Advanced > Certificates (meu Firefox está em inglês), estava lá. Mas o Firefox continuava dizendo que o site não era confiável. 

Procurei um pouco, perdido. Fui olhar a VM de Linux, lá ainda funcionava, com o mesmo código. Um tempo depois, olhei a versão do Firefox. A última atualização era recente, 13 de junho, versão 54. Falava em mudanças de segurança, mas dizia que era CSS. Corri um pouco mais atrás do meu rabo. Fui no Linux. A versão era anterior. Atualizei. Parou de funcionar também!

Quase desisti nesse momento. Até que alguém visse isso, em algo tão recente, até que incomodasse gente suficiente...

Comecei a testar fazer outras coisas. Mudei a permissão usada ("TCu,Cuw,Tuw"). Reli o erro, que falava de Issuer. Adicionei o certificado Root no Firefox também. No meio do caminho descobri uma coisa útil: o certutil tem uma opção -V, que valida parcialmente o certificado. Adicionando CA ainda não funcionava. Tentei com alguns tipos de permissão, erros diferentes aconteciam. Quase desistindo de novo.

Fui até o Firefox e tentei adicionar o certificado na mão. Deu uma mensagem de erro, ao contrário do que o certutil fazia - que simplesmente adicionava. Sobre o parcialmente: o mesmo certificado que deu como válido no -V apontou inválido no Firefox direto. Procurei a mensagem no Google. Descobri que precisava de uma flag no certificado CA, em extensions, uma basic extension com valor CA=true.

Resumo da ópera:
Adicionar certificado CA:
certutil.exe -d [cert8.db path] -A -t "TC,," -n [name] -i [crt path]

Adicionar certificado SSL:
certutil.exe -d [cert8.db path] -A -t "u,," -n [name] -i [crt path]

Em C#, usando BouncyCastle, para adicionar o CA=true:
var generator = new X509V3CertificateGenerator();
(...)
var basicContraint = new BasicConstraints(true);
generator.AddExtension(
    X509Extensions.BasicConstraints, true, basicContraint
);

Voilá! Funcionou de novo. E pude ir feliz pra casa na segunda. Ao contrário de sexta, quando descobri o final do dia que tinha feito uma co

sexta-feira, 3 de junho de 2016

GUIDs no MySql com NHibernate


Não faça isso!

Outro dia estava mexendo com GUIDs com NHibernate e Mysql e publiquei o seguinte post:

Procurei de diversas maneiras como colocar Guid em mysql usando NHibernate. NHibernate até aceita, quando vai validar o banco, que você use o binary(16), mas, na hora de gravar, reclama que o valor é muito grande para o campo.

Continuei procurando e diversas pessoas recomendam que se use varchar(36) (32 caracteres alfanuméricos + 4 traços). Procurando "nhibernate mysql guid as binary" encontrei este link do stackoverflow:
http://stackoverflow.com/questions/1295007/problem-with-nhibernate-mysql-and-guids

Colocando "old guids=true;" no final da connection string é o NHibernate consegue salvar o valor na base (se o último caracter não for ";", lembre de colocar um ";" antes).



Hoje descobri que o programa passou a interpretar qualquer coisa com 32 caracteres de 0 a F como guid e reclamar. O jeito que encontrei foi recriar a base de dados.

Então... NÃO FAÇA ISSO! Use varchar(38) e seja feliz.

sexta-feira, 29 de abril de 2016

Trocar a Url de update do ClickOnce *

Você publica seu programa para ser baixado em uma certa URL. E está tudo certo, faz outros deploys, os clientes baixam felizes. Então você resolve mudar a pasta que está usando para fazer o update, por quaisquer motivos. E o ClickOnce dá erro no update, porque baixou de urls diferentes, e recomenda que você desinstale o programa original, baixe o novo e instale de novo.

Existem diversos passo-a-passo na web de como fazer isso, incluindo mageui, alterações direto na configuração do projeto do programa, etc. A ideia é fazer um deploy intermediário, que estaria na pasta antiga, mas apontaria o update para a nova pasta. Não funciona, o clickonce ainda reclama da nova url.

O que funcionou de verdade foi colocar um url rewrite no web.config da pasta de publish original. Quando o programa bate nessa pasta, ela passa a devolver o conteúdo da outra pasta. Na outra pasta, o programa será baixado com a nova url de update. Este seria o código a adicionar no web.config da pasta antiga, dentro de <system.webServer>:

        <rewrite>

            <rules>
                <clear />
                <rule name="Redirect New Path" stopProcessing="true">
              
                    <match url="^(.*)$" />
                    <action type="Rewrite" url="/[aqui você coloca a nova pasta]/{R:1}" redirectType="Temporary" appendQueryString="true" />
               
                </rule>
            </rules>

        </rewrite>




* ClickOnce é uma ferramenta do Visual Studio para fazer deploys / updates nos programas que você cria lá

terça-feira, 8 de março de 2016

Erro ao iniciar o MySQL Workbench

Tive um erro tentando iniciar o MySQL Workbench. Erro de windows mesmo. Abri a janela de detalhes e tentei ver quais informações poderiam ser úteis para buscar. Me pareceram estas:

Fault Module Name:    KERNELBASE.dll
Error Code:                    e0434352

Busquei e comecei a achar as mais diversas coisas. Uma pessoa disse que teve que trocar de windows pra funcionar. Então lembrei que tínhamos acabado de desinstalar o Visual Studio da máquina, fazia alguns dias. E pensei que talvez isso tivesse levado algo do Workbench junto.

Entrei na página do Workbench pra reinstalar. Baixei. Na instalação, o programa detectou que faltavam um pré-requisito: Microsoft Visual C++ 2013 Redistributable Package (x86 or x64). Fui pra página de pré-requisitos. Baixei o C++. Instalei.

Ia continuar a instalação do Workbench. Mas parei, pensei e fui testar se o que estava instalado funcionava. E não é que o bichinho tinha voltado?

Postando porque pode ser que a pessoa ache um bilhão de soluções mirabolantes, do tipo reinstalar o windows, e não precisa de tudo isso.

quinta-feira, 8 de outubro de 2015

Problema com wi-fi no windows 10

E aí eu instalei o windows 10 no computador de casa antes de instalar no do serviço. Vai que dá algum problema, né?

Tudo lindo, rodando, testei alguns dias, sem problemas. Mandei instalar no do serviço. Fui pra casa. Cheguei hoje... Liguei... Bonitinho... Abre o browser... Pera, cadê a Internet? Será que ele apagou as configurações de wi-fi? Como assim, que wi-fi?

Pois é, nem a luzinha do note de wi-fi tava mais acendendo. Tentei reiniciar. Nada. A mensagem era que o serviço de Wi-fi (WLAN AutoConfig) não estava startado. Fui na esperança, mandei o Start, deu "Windows cannot start the WLAN Autoconfig service on local computer". Ah, que bom, starta no computador do vizinho pra mim então.

Quando fui instalar, ele relatou incompatibilidade do software de VPN. Mas em casa também tinha dado isso e correu tudo bem. De qualquer forma, fui lá e desinstalei. Cisco VPN, está em Programs and Features, no Control Panel. Reiniciei com shutdown -r -t 0 porque tava sem paciência. Nada. Tentei usar uma internet de cabo para verificar se os drivers estavam atualizados. Funcionavam normal.

Reiniciei de novo, dessa vez com shutdown -r apenas. Deu tela azul (aeeee! Conhecia a tela azul do windows 10 em menos de uma hora de uso neste computador!). Reiniciou. Estava normal. Minha wi-fi de volta.

terça-feira, 1 de setembro de 2015

Problemas com a biblioteca apache no android 6

Fiquei duas horas e meia tentando resolver ontem, mais uma hora e meia hoje. Meu problema era um erro que encontrei no meu projeto, com a biblioteca do apache, para fazer webrequests. Achava que o problema era a migração para o Android Studio. E eu não pretendo voltar ao eclipse.

O erro que aparece é:

"error: package org.apache.http does not exist"

Procurei na internet e encontrei diversas recomendações. A primeira foi adicionar uma biblioteca do apache na lista de dependencies. Adicionei, mas ele ainda não encontrava a classe org.apache.http.client.utils.URLEncodedUtils. Uma outra sugestão foi forçar o uso da biblioteca apache, colocando o código android { useLibrary 'org.apache.http.legacy' } no gradle.

Encontrei pessoas falando para usar uma biblioteca chamada Volley, que deve substituir a do apache. E pensei em ajustar o projeto para usar. Descobri que a LVL, biblioteca do android para verificar licença, não está adaptada. Não encontrei qualquer versão dela que estivesse. Mesmo a versão oficial do site. Só bastante gente xingando por não terem adaptado ainda, pois a versão Marshmallow do android (6.0) vai cortar a biblioteca apache.

Nesse momento, me dei conta de que tinha atualizado o arquivo gradle para usar a última API do Android, a 23, do Marshmallow, assim que migrei para o Android Studio. Estava usando a API 19 como máxima antes, muito atrasado. Mudei para 22. Tudo voltou a funcionar.