Android. Выполнение задач в бэкграунде.

Posted by Olegas on Январь 23, 2012
IT / Нет комментариев

На Stackoverflow часто встречаются вопросы по выполнению на Android фоновых задач, в т.ч. и повторяющихся с заданным промежутком времени. Как правило, первое, что используется, это Service.

Такой подход в некоторых случаях может привести к тормозам и низкой скорости ответа пользовательского интерфейса. Расскажу когда так бывает и как с этим бороться…
Читать далее…

Тэги: ,

Почему Mac?

Posted by Olegas on Январь 22, 2012
IT / Комментарии: 3

Когда я выбирал для себя модель будущего ноутбука я советовался с друзьями и знакомыми. Многие, услышав, что я выбрал ноутбук стоимостью порядка 40к и узнав что это не Mac искренне удивлялись – «За такие деньги и не Mac? Если есть столько денег – бери только Mac». Никто толком не мог объяснить почему. Далее «ну, это же круто» обычно дело не шло.

За время пользования я обнаружил для себя некоторые субъективные достоинства но есть один объективно важный для разработчика плюс. На маке все есть. Покупая Mac в нем уже есть из коробки

  • Python
  • Perl
  • PHP
  • Ruby
  • … ну и еще много всего

К чему бы все это богатство нужно если вы, например, PHP-программист, веб-разработчик которому это все барахло совсем даже поровну, что есть что нет… Все дело в сторонних инструментах. Возьмем например SASS. Написан он на Ruby. И вот на винде тебе нужно пойти, найти и скачать инстяллятор, накатить это все, потом уже накатить  SASS… На Mac ты просто пишешь в консоли gem install sass и начинаешь пробовать.

Та же песня со всякими вещами типа Node.JS и NPM к нему. На винде нужно уметь плясать с правильной моделью бубна чтобы все это зажило (до 6 версии по крайней мере это было так). Здесь ты просто выполняешь не сильно сложные инструкции с сайти или качаешь готовый дистр и уже можно начинать экспериментировать с новым инструментом.

Тэги:

Непонятная проблема при отдаче статического контента…

Posted by Olegas on Ноябрь 19, 2011
Без рубрики / Комментарии: 4

Необычную проблемы обнаружили на работе…

Есть сайт – статика + ISAPI-расширение. Статика на 90% состоит из XML и JS. Ее много.

Вот диаграмма загрузки кучи статики в Firefox. Как видно – все в порядке.
Диаграмма загрузки Firefox

А теперь то же самое в IE8.

Диаграмма загрузки IE

На обоих изображених подчеркнуты запросы с одинаковым размером (чтобы было проще ориентироваться). Порядок разный потому что вызывают их различне асинхронные процессы и это (порядок) для работы приложения не важен.

Видно 3 проблемных места. В точке 1 запросы начали подтормаживать (темно зеленый – время отдачи контента, по размеру видно что отдавать там нечего). Следующая пачка параллельных запросов (точка 2) зависает еще сильнее (до 5 сек.), и снова по размеру понятно что не на чем там столько сидеть. Следующая проблемная точка (3) висит уже не на отдаче, а на приеме сервером (?, в легенде это называется «send first to last») пакета данных (POST) и снова по размеру понятно что отправлять там целых 1.5 сек. совершенно нечего…

На сервере IIS 7.5, замеры проводились на одной и той же клиентской машине в одно и то же время. Проблема не зависит от клиентской машины и проявляется на других маинах в сети аналогичным образом. В Event log’е винды пусто.

Мошеннические Android-приложения…

Posted by Olegas on Сентябрь 27, 2011
IT / Комментарии: 1

Поскольку я являюсь разработчиком Android-приложения, то слежу за появлением новых ссылок на него с помощью подписок Google. Сегодня утром я с радостью обнаружил в ящике письмо, в котором присутствовала новая ссылка на мое приложение. Все отлично! И отзыв положительный, и количество загрузок отличное от 0 вот только версия почему-то старая и… размер APK целых 3 мегабайта против оригинальных ~200К

После загрузки и распаковки APK (вспоминаем что APK это просто ZIP-архив) в нем обнаружилась «набивка» из 153 PNG файлов (переименованных зачем-то в .temp) со свидетелем из Фрязино и собственно «приложение»…

Как и следовало ожидать, от оригинального приложения там ничего не осталось. Ни иконки, ни, тем более, кода. А при дальнейшем рассмотрении (похоже что) ВСЕ файлы на androides-os.com – одна и та же программа! Я скачал несколько разных программ из разных разделов и все они были одного размера и с одинаковым содержимым!

Внутри оказалось нечто, которое по беглому анализу ресурсов оказалось приложением, запрашивающим активацию путем отправки SMS. Попробуем разобраться, куда и что отправляется…

Читать далее…

Тэги: ,

Посетил YaC 2011

Posted by Olegas on Сентябрь 21, 2011
Без рубрики / Нет комментариев

Посетил YaC 2011 (Yet another Сonference) от Яндекс. Это была вторая чисто техническая конференция, на которой мне посчастливилось поприсутствовать. Первая – ADD (Application Developer Days) 2010 в Ярославле. Далее кратко по пунктам…

  • Это было супер офигенски круто. Организация, доклады, атмосфера – все на высоком уровне. Спасибо оргам. Робот Марвин свободно ездящий по территории – это 5. Мешки, юла-стулья, тематические мероприятия («Настрой Ngninx за 10 минут») и стенды – просто супер.
  • Доклад Алексея Воинова про экзотические языки – замечателен, смело меняем название на «Зачем программисту ходить на технические конференции» и вкладываем в уши всем работодателям, кто еще сопротивляется отпускать своих сотрудников, мотивируя практической бесполезностью происходящего.
  • Роботы, тестирующие веб-сервисы от Артема Ерошенко – супер, отличная идея методики автоматизированного тестирования верстки.
  • Познакомился с Дмитрием @dr_zhest Жестилевским. Отлично выпили пива и пообщались в кабаке после мероприятия =)
  • Из грусти: WiFi – его качество немного скрашивало позитив. Если на его отсутствие во время докладов можно было смело забить, то отсутствие его на мастер-классах по BEM сделало участие в них крайне сложным. Возможно помогли бы шнурки или отдельная запароленная сеть с выдачей доступов на самом мастер-классе. Впрочем, как правильно заметил bobuk на круглом-столе – WiFi всегда проблема на подобных мероприятиях.
  • И все же, то, как Яндекс в BEM использует NodeJS, натолкнуло на определенные практические мысли относительно текущего рабочего проекта. Profit!

Еще раз Спасибо всем организаторам и докладчикам за офигенское мероприятие. Ждем YaC 2012!

Делаем простейший сборщик ошибок для Android

Posted by Olegas on Июль 11, 2011
IT / Нет комментариев

При разработке приложения неизбежно приходится сталкиваться с ошибками в коде и/или окружении. И очень печально когда подобные ошибки встречаются не на тестовом телефоне/эмуляторе а у живых пользователей. Еще печальнее если это не ваш друг бета-тестер и толком никто не может объяснить что и где свалилось.

Обычно при внезапном падении приложения Android предлагает отправить отчет об ошибке, где будет и подробный стэк-трейс и информация о версии вашего приложения. К сожалению пользователи не всегда нажимают кнопку «отправить отчет» а для дебаг-приложений или приложений не из маркета такая функциональность и вовсе недоступна.

Что же делать? На помощь приедет возможность языка Java обрабатывать исключения (Exceptions), в том числе и непойманные (unhandled).

Читать далее…

Тэги: ,

Занятный баг с TabHost в Android 2.1

Posted by Olegas on Май 04, 2011
IT / Нет комментариев

Обнаружили с коллегой занятный баг в Android, связанный с работой TabHost.

Суть в следующем. Если после onCreate в вашей TabActivity внутри TabHost не будет создано ни одной корректной вкладки все хозяйство с треском осыпается. Причем стэк очень интересный. По нему сложно выявить причину ибо в нем нет ничего, кроме кода ядра ОС.

Выглядит примерно так

Exception: java.lang.NullPointerException
Message: null
Stacktrace:
        android.widget.TabWidget.dispatchDraw(TabWidget.java:241)
        android.view.ViewGroup.drawChild(ViewGroup.java:1565)
        android.view.ViewGroup.dispatchDraw(ViewGroup.java:1294)
        android.view.ViewGroup.drawChild(ViewGroup.java:1565)
        android.view.ViewGroup.dispatchDraw(ViewGroup.java:1294)
        android.view.ViewGroup.drawChild(ViewGroup.java:1565)
        android.view.ViewGroup.dispatchDraw(ViewGroup.java:1294)
        android.view.View.draw(View.java:6588)
        android.widget.FrameLayout.draw(FrameLayout.java:383)
        android.view.ViewGroup.drawChild(ViewGroup.java:1567)
        android.view.ViewGroup.dispatchDraw(ViewGroup.java:1294)
        android.view.View.draw(View.java:6588)
        android.widget.FrameLayout.draw(FrameLayout.java:383)
        com.android.internal.policy.impl.PhoneWindow$DecorView.draw(PhoneWindow.java:1869)
        android.view.ViewRoot.draw(ViewRoot.java:1384)
        android.view.ViewRoot.performTraversals(ViewRoot.java:1149)
        android.view.ViewRoot.handleMessage(ViewRoot.java:1668)
        android.os.Handler.dispatchMessage(Handler.java:130)
        android.os.Looper.loop(Looper.java:154)
        android.app.ActivityThread.main(ActivityThread.java:4416)
        java.lang.reflect.Method.invokeNative(Native Method)
        java.lang.reflect.Method.invoke(Method.java:552)
        com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:910)
        com.android.internal.os.ZygoteInit.main(ZygoteInit.java:668)
        dalvik.system.NativeStart.main(Native Method)

Лечится, очевидно, корректной подготовкой табов в onCreate. Что интересно, в 2.2 такого бага уже нет.

Тэги: ,

Интеграционное тестирование web-приложения с Selenium WebDriver

Posted by Olegas on Февраль 17, 2011
IT / Нет комментариев

Интеграционное тестирование (в отличие от Unit- или модульного тестирования) это тестирование не отдельных атомарных компонентов системы (классов) а результата их взаимодействия между собой в какой-либо среде.

Волею судеб я занимаюсь разработкой своего рода интерфейсного фреймворка заточенного на определенные корпоративные нужды. Среда исполнения фреймворка – браузер, а по сему язык – JavaScript.

О том, как можно Unit-тестировать JavaScript я писал ранее, сейчас же расскажу о процессе интеграционного тестирования, применяемого в команде.

Selenium

С давних времен известен инструмент тестирования веб-приложений/страниц в браузере – Selenium. В плане его применения есть два основных пути, а именно:

  1. написание TestSuite в SeleniumIDE и прогон их через SeleniumTestRunner, или
  2. использование WebDriver

WebDriver это новая «фишка» Selenium, появившаяся во второй ветке продукта. Основная его суть – можно гонять тесты, описанные в коде (C#, Java), в разных браузерах и/или в виртуальной среде исполнения.

WebDriver

Selenium WebDriver это набор «биндингов» к разным языкам (C#, Java), позволяющий отдавать различные команды «подчиненному» браузеру.

Для каждого браузера имеется своя реализация WebDriver (FireFoxDriver, InternetExplorerDriver, ChromeDriver – сейчас включены в поставку, OperaSoftware разработали OperaDriver). Существует также «виртуальный» HtmlUnitDriver. В отличии от «браузерных» реализаций он не требует установленного браузера и за счет этого работает быстрее и платформонезависим, но есть и минусы – HtmlUnitDriver имеет «свою» реализацию JavaScript и потому поведение «богатых» веб-приложений может в нем отличаться. Для своих задач мы используем «браузерные» реализации, это позволяет проверить приложение именно в той среде, в которой оно будет исполняться впоследствии.

Кратко общая суть работы с WebDriver может быть описана так:

  • реализуется код, использующий какую-либо имплементацию WebDriver. Данный код выполняет какие-либо действия с веб-страницей и сравнивает результат с эталонным
  • WebDriver транслирует команды в запущенный браузер (при использовании «браузерной» реализации) и сообщает результаты «обратно в код»

Что умеет WebDriver

Ниже рассматривается «браузерная» реализация, суть расширение класса RemoteWebDriver (реализует интерфейс WebDriver).

  • поиск элементов: findElement(s)By*
    • CssSelector
    • ClassName
    • Id
    • LinkText
    • TagName
    • XPath
  • загрузка страницы, получение контента страницы
  • исполнение произвольного JavaScript
  • осуществление операций Drag-n-Drop

C «найденными» элементами (интерфейс WebElement)

  • получение текста (text)
  • получение значения (value)
  • click по элементу
  • ввод с клавиатуры (клавиша, сочетание клавиш, последовательность клавиш/сочетаний)

Среда исполнения тестов

В качестве языка для написания тестов была выбрана Java. Среда для исполнения – JUnit4.

Базовый абстрактный класс веб-тестов.

@Ignore
abstract public class AbstractWebTest {

    protected static RemoteWebDriver _driver;
    // расположение тестовой страницы
    private String testPageLocation =
                String.format(
                        "http://%s:%s/test.html",
                        System.getProperty("test.httproot"),         // Web-сервер ...
                        System.getProperty("test.httpport", "80")   // и порт
                );
    // Используемая имплементация WebDriver
    private static String driverName =
                System.getProperty(
                        "test.driver",
                        "org.openqa.selenium.firefox.FirefoxDriver");

    /**
     * Перед каждым набором тестов - создаем инстанс драйвера.
     * Это автоматически запустит браузер
     */
    @BeforeClass
    public static void setUpDriver()
                throws ClassNotFoundException,
                          IllegalAccessException,
                          InstantiationException {
        _driver = (RemoteWebDriver) Class.forName(driverName).newInstance();
    }

    /**
     * Перед каждым тестом - открываем тестовую страницу
     */
    @Before
    public void setUp() {
        _driver.get(testPageLocation);
    }

    /**
     * После каждого набора тестов - закрываем инстанс дарйвера (закрываем браузер)
     */
    @AfterClass
    public static void tearDown() {
        _driver.close();
    }
}

Конкретный класс с набором тестов (для простоты убраны некоторые проверки, например на то, что элемент по CSS-селектору действительно найден и доступен на странице)

public class TestMoneyField extends AbstractWebTest {

    /**
     * При рендеринге поле ввода денежной суммы должно показать 0.00
     */
    @Test
    public void testRendering() {
        WebElement content =
           _driver.findElementByCssSelector("#FieldMoney .input-text-field");
        Assert.assertEquals("0.00", content.getValue());
    }

    /**
     * Проверим форматирование "триад"
     */
    @Test
    public void testInputWithoutDot() {

        WebElement content =
           _driver.findElementByCssSelector("#FieldMoney .input-text-field");
        content.sendKeys("999999");
        Assert.assertEquals("999 999.00", content.getValue());
    }
}

Все тесты запускаются с помощью отдельного таска Ant-билда:

<target name="integrationtest" depends="init, buildtests, deploytests">
   <junit haltonfailure="false">
      <sysproperty key="test.driver" value="org.openqa.selenium.firefox.FirefoxDriver" />
      <classpath>
         <pathelement location="${path.to.tests.jar}"/>
      </classpath>
      <batchtest>
         <fileset dir="${path.to.compiled.test.classes}">
            <include name="**/tests/Test*.class" />
         </fileset>
      </batchtest>
   </junit>

   <junit haltonfailure="false">
      <sysproperty key="test.driver" value="org.openqa.selenium.ie.InternetExplorerDriver" />
      <classpath>
         <pathelement location="${path.to.tests.jar}"/>
      </classpath>
      <batchtest>
         <fileset dir="${path.to.compiled.test.classes}">
            <include name="**/tests/Test*.class" />
         </fileset>
      </batchtest>
   </junit>
</target>

Данный таск прогонит все известные тесты из классов, чьи имена начинаются с Test под браузерами Firefox и InternetExplorer. В зависимостях таски с базовой инициализацией, компиляцией и выгрузкой скомпилированных тестов на тестовую площадку.

Фишки-плюшки

Некоторые «браузерные» реализации (Firefox, Opera, Chrome) поддерживают снятие скриншотов. Это может быть полезно дабы зафиксировать визуальное состояние, в котором пребывала тестовая страница в момент, когда тест не прошел. Для этого подойдет функционал JUnit4 – TestWatchman.

@Ignore
abstract public class WISbisTest {

    // Папка для скриншотов
    private String screenshotDir =
            System.getProperty("test.screenshotDir", "");

    @Rule
    public MethodRule watchman = new TestWatchman() {

        /**
         * Будет вызван при каждом "проваленном" тесте
         * @param e Брошенное тестом исключение
         * @param method Тест-метод
         */
        @Override
        public void failed(Throwable e, FrameworkMethod method) {
            if(_driver instanceof TakesScreenshot && !screenshotDir.equals("")) {
                String browserName = _driver.getClass().getName();
                String testSuiteName = method.getMethod().getDeclaringClass().getName();
                browserName =
                        browserName.substring(browserName.lastIndexOf('.') + 1);
                testSuiteName =
                        testSuiteName.substring(testSuiteName.lastIndexOf('.') + 1);

                byte[] screenshot =
                        ((TakesScreenshot)_driver).getScreenshotAs(OutputType.BYTES);
                try {
                    FileOutputStream stream =
                            new FileOutputStream(
                                    new File(
                                        String.format("%s/screenshot_%s_%s_%s.png",
                                                screenshotDir,
                                                browserName,
                                                testSuiteName,
                                                method.getName())));
                    stream.write(screenshot);
                    stream.close();
                } catch (IOException e1) {
                    e1.printStackTrace(System.out);
                }
            }
        }
    };
    // все остальное...

}

Добавим переменную с путем к папке со скриншотами в Ant-билд

   <junit haltonfailure="false">
      <sysproperty key="test.driver" value="org.openqa.selenium.firefox.FirefoxDriver" />
      <sysproperty key="test.screenshotDir" value="${screenshotsDir}" />
      <classpath>
         <pathelement location="${path.to.tests.jar}"/>
      </classpath>
      <batchtest>
         <fileset dir="${path.to.compiled.test.classes}">
            <include name="**/tests/Test*.class" />
         </fileset>
      </batchtest>
   </junit>

Интеграция

В текущей реализации Ant-билд гоняется через Jetbrains TeamCity. Запуск билда настроен на сброс кода в SVN. Интеграционные тесты – часть общей процедуры тестирования. При провале любого из интеграционных тестов снимается скриншот и публикуется как «артефакт» билда – можно видеть не только какие тесты «отъехали» после сброса в транк какого-либо функционала, но и увидеть «как» они «отъехали».

В настоящее время используется тестирование под IE и Firefox, Chrome не подключен по причине некоторых трудностей с интеграцией (судя по всему в ChromeDriver присутствуют некоторые ошибки, не позволяющие нормально искать элементы на странице в некоторых случаях – по состоянию на 2.0b1, сейчас доступна 2.0b2 но работу с ней пока не пробовали)

Тэги: , , ,

JavaScript. Юнит-тестирование и CodeCoverage

Posted by Olegas on Октябрь 06, 2010
IT / Комментарии: 2

В этой заметке расскажу о своем опыте юнит-тестирования JS-кода, опыте использования среды выполнения тестов js-test-driver, ее возможности code coverage и скручивании ежа с ужом, а именно данных о code coverage от js-test-driver и генератора отчетов о покрытии PHP_CodeCоverage. Сам результат скручивания можно будет поглядеть и потрогать руками…
Читать далее…

Тэги: , ,

Пробки на Я.Картах – изменился адрес сервера с тайлами

Posted by Olegas on Июль 02, 2010
IT / Нет комментариев

Недавно Яндекс поменял адрес сервера с тайлами пробок. Теперь вместо trf.maps.yandex.net надо использовать jgo.maps.yandex.net.

Спасибо за багрепорт и новый хост проекту http://chelmaps.ru

Тэги: