LINUX.ORG.RU

Сообщения DRVTiny

 

Высвобождение памяти (free) - когда НЕ происходит?

Форум — Development

Читал я как-то на заборе, что perl якобы единожды выделенную ему память обратно системе старается не возвращать, а прямо-таки держит до последнего.

Ну написал простенький тест:

#!/usr/bin/perl
use MIME::Base64 qw(encode_base64);
use Time::HiRes qw(sleep);
open my $fh, '<', '/dev/urandom';
my $N=shift or die 'FYAH';
sub fillHash {
  my ($N,$hsh,$fh)=@_;
  my $randBase=$N*10;
  for (1..$N) { 
    read $fh, $s, 1024; 
    $hsh->{int(rand $randBase)}=encode_base64($s);
  }
}

my %H;
while (1) {
  fillHash($N,\%H,$fh);
  sleep 0.2;
  %H=();
}

В итоге, что и логично было бы предположить, потребление памяти не меняется со временем.

Но всё же... в каких ситуациях Perl и в самом деле может не вполне очевидным образом забрать память и не отдать её системе? Скажем так, насколько лениво Perl делает free на структурах данных в примерах, аналогичных моему тесту?

Спасибо!

 

DRVTiny
()

Простенькие и удобные функции логирования

Форум — Development

Задумался я как-то невзначай над тем, почему строки для trace и debug формировать труднее всего, но при этом они же чаще всего вообще не выводятся никуда. Ведь несправедливо же: интерпретатор старается, формирует какие-то дампы, куски json'ов вставляет - а мой любимый фремйворк для логирования, Log::Log4perl, всё это радостно сливает в /dev/null.

Также очень не хватало возможности выводить лог-сообщения в нормальном sprintf-стиле: я думаю, многих достала необходимость конкатенации строк для вставки переменных или использования для компиляции строки самой sprintf. Ну неудобно это! Мне куда легче не использовать %s и прочие немногочисленные валидные форматеры printf в тексте лог-сообщений, нежели каждый раз задумываться над тем, как собрать строку лога из разрозненных кусков.

Порылся я немного в поисках решения задачи - и нашёл Log::Contextual - вроде бы делает он всё как нужно, и вместо самой строки потребно отдавать ему блоки кода, в которых и формировать строки. Если уровень логирования ниже требуемого - блок просто не будет выполнен.

Но как-то решил я невзначай порыть исходники этого модуля - и узрел, что там гигантский пласт кода, который делает что-то совершенно хакерски-химерическое (код самого Log::Log4perl проще и понятнее в $N раз), позволяет подключать все подряд фреймворки... Это всё было очень круто конечно, но мне с одной стороны не нужны были другие фреймворки, а с другой - не хотелось бы, чтобы поверх и без того относительно тяжёлого Log::Log4perl ещё гора кода наросла. Ну и встроенная sprintf-функциональность из-за тотальной универсальности логеров ни в одном из них не была реализована, в том числе и в Contextual.

В итоге я сломался и сделал свой велосипед: https://github.com/DRVTiny/Log4perl--KISS

Он позволяет делать как

debug {'String'}
, так и
debug_ 'String'
, что, собственно, мне и было в конечном итоге нужно.

Подробнее - см в SYNOPSIS прилагающегося README.

Относительно устранения гипотетического конфликта форматеров sprintf и логируемого содержимого - есть идеи как это реализовать :) Но в любом случае конечно только сам логирующий знает, могут в его контенте попадаться форматеры или нет.

 ,

DRVTiny
()

Контрабанда с использованием дронов: возможно ли?

Форум — Talks

Ммм... Возникла у меня такая мысль: интересно, а контрабандисты могут использовать для перевозки чего-либо мелкого - управляемые дроны? Ну, те самые четырёхпропеллерные штуки, которым запретили недавно летать без «лётного удостоверения летуна». Мне кажется, в тех местах, где есть «приграничные» города и деревни, дрон с приличным аккумулятором мог бы пролететь достаточно далеко за контрольно-следовую полосу, чтобы приземлиться там, где житель приграничной зоны (коему по определению разрешено по ней перемещаться, поскольку там его дом) мог бы подобрать дрона и переправить его содержимое дальше.

Или у дронов с дальностью полёта всё совсем плохо?

 

DRVTiny
()

Как найти определение структуры данных в большом C-проекте

Форум — Development

Товарищи, скажите, как не используя GUI и не сочиняя однострочников на perl'е, открыть проект на C из огромной груды файлов и найти в нём определение структуры данных? Структура используется в миллионе разных мест, поэтому найти именно определение оказалось что-то не так и просто.

Вообще возможно ли такое чудо в 2017-м году из консоли?

cscope -R использовал, ничего не нашёл. Может, есть ещё какие-то варианты? Всё-таки космические корабли уже бороздят просторы космоса, да и задача, должно быть, типовая в мире OpenSource: открыть чужие исходники, что-нибудь поправить в них. Ведь для этого надо же мне знать, как и где определена та структура данных, которой я пользуюсь?

P.S. Речь о zbx_vector_ptr_t в исходниках Zabbix-сервера.

 , , ,

DRVTiny
()

Чем сейчас принято mmap'ить файлы?

Форум — Development

Возникла странная проблема: открываю файл с PerlIO layer'ом ":mmap", делаю на нём binmode($fh), пишу туда данные CBOR-кодированные. Ну и отправлюсь в глубокий сон AE::cv->recv

Потом открываю этот файл:

use 5.16.1;
use Time::HiRes qw(time);
open my $fh, "<:mmap", "/tmp/mmap.15669";
binmode($fh);
use CBOR::XS qw(decode_cbor);
my $s=time();
my $csh3=do{local $/;<$fh>};
my $h=decode_cbor($csh3);
print (time()-$s)," sec\n"
(на самом деле это однострочник :))

И получаю:

unexpected end of CBOR data, at offset 2326528 (octet 0x00) at -e line 1, <$fh> line 1.

При этом реальный размер записанных данных - 2329390. Т.е. запинается явно не на кривом конце файла или чём-то подобном.

Отсюда возник вопрос: возможно, я как-то не так пользуюсь layer'ом?

А может, стоит использовать Sys::Mmap (говорит: permission denied при попытке открыть для mmap'а несуществующий файл в /tmp) или File::Map? Или ещё что-то...

Мне нужно просто расшарить кусок дико бинарных данных между процессами: записать его один раз, сказать всем процессам через ZMQ (раз уж IPC почему-то не в фаворе у современных программистов), что «нате, забирайте свой бинарный шит» каждый процесс возьмёт заmmap'леное содержимое чудо-файлика, decode_cbor'ит его - и будет счастье.

Но что-то не срастается нифига, не могу понять, почему :(

Any ideas?

 ,

DRVTiny
()

Можно ли в Mojo-приложениях использовать главный процесс?

Форум — Development

Есть у меня приложение на Mojo (работает под hypnotoad), его список процессов выглядит следующим образом:

$ pstree -p $(</opt/WebServices/druid2/run/hypnotoad.pid)
/opt/WebService(7038)─┬─/opt/WebService(7039)
                      ├─/opt/WebService(7040)
                      ├─/opt/WebService(7041)
                      ├─/opt/WebService(7042)
                      ├─/opt/WebService(7043)
                      ├─/opt/WebService(7044)
                      ├─/opt/WebService(7045)
                      ├─/opt/WebService(7046)
                      ├─/opt/WebService(7047)
                      ├─/opt/WebService(7048)
                      ├─/opt/WebService(7049)
                      ├─/opt/WebService(7050)
                      ├─/opt/WebService(7051)
                      ├─/opt/WebService(7052)
                      ├─/opt/WebService(7053)
                      └─/opt/WebService(7054)
$ sudo netstat -pna | fgrep :8097
tcp        0      0 0.0.0.0:8097            0.0.0.0:*               LISTEN      7038/druid          

Мне очень хотелось бы сделать следующее: после всех форков процесса 7038, нужных для создания воркеров, сделать ещё один форк, но особый - этот форк создаст процесс для выполнения «служебных» задач, в данном конкретном случае - для обновления кеша. Т.е., условно будет форкнут процесс №7055, который будет подогревать кеш для чтения его в процессах №№7039-7054.

Кто-нибудь пробовал делать подобное в рамках одного приложения или единственный вариант - обновление кеша вообще в отдельном демоне, просто шарящем один файл через mmap с процессами Mojo-приложения?

Попытаюсь реализовать с помощью Mojo::IOLoop::ForkCall, но возможно есть варианты лучше.

Также есть более фундаментальная проблема: в данный момент кеш существует для каждого процесса отдельно в виде самого обычного perl-хеша. Реализован следующим образом:

  • Есть обновляемый и перезагружаемый извне кеш 1-го уровня, это Redis;
  • Каждый процесс делает подписку (subscription) в Redis для получения JSON-сообщений вида: «у объектов (ключи хеша) изменились атрибуты (значения хеша)» и на сообщения «кеш 1-го уровня перезагружен целиком»;
  • При старте, т.е. в Mojo::IOLoop->next_tick, каждый процесс читает весь кеш 1-го уровня, подписывается на сообщения об изменениях этого кеша. При получении сообщений об изменениях - каждый процесс-воркер обновляет свой perl'овый хеш-массив для того, чтобы тот соответствовал текущему состоянию Redis.

Чем плоха описанная схема?

  1. При получении сообщений о полной перезагрузке кеша 1-го уровня - все процессы дружно лезут читать его целиком. А кеш довольно большой по объёму. В этот момент, ясное дело, процессы не могут отвечать на запросы пользователей - т.е. не могут все одновременно :) Теоретически это можно обойти, существенно реже обновляя кеш 1-го уровня целиком.
  2. Каждый процесс хранит у себя хеш-полную копию кеша 1-го уровня, а каждая такая копия занимает порядка 10Мб в памяти. Вроде бы пустячок, но контроллер памяти - не резиновый, и не слишком рассчитан на то, чтобы копии абсолютно одних и тех же данных читались из 16-ти разных мест
  3. Если вдруг какой-то процесс не получит сообщение об обновлении или обработает его по каким-то причинам позже других - его «версия реальности» резко разойдётся с версиями всех остальных процессов - и в итоге мы получим на один запрос бэкенда свежие данные, а на следующий (при передаче управления залипшему процессу) - уже устаревшие данные.

Возможно, я что-то дурю и то, как оно есть - это уже вполне рабочий вариант (не могу сказать, что сейчас всё это хозяйство работает медленно - вроде даже вполне приемлемо)? Просто у варианта с кешом 2-го уровня в виде Cache::FastMmap есть как минимум один существенный недостаток: он работает в разы медленнее простого Perl-хеша...

 , ,

DRVTiny
()

Лаконичный способ получить число ядер процессора в Linux?

Форум — Development

Есть ли у кого варианты короче данного?

say $n=do { open $_,"</proc/cpuinfo"; grep {!index($_,"\n")} <$_> }

Ещё:

say $n=scalar(@{$_}=</sys/bus/cpu/devices/*>)

 

DRVTiny
()

Смысл graphite, prometheues и opentsdb?

Форум — Talks

Не понимаю, в чём собственно смысл систем мониторинга, которые не являются по факту системами мониторинга: ни сборщиков данных, ни расчёта триггеров. А без этого - зачем нужны графики? Даже если какие-то чудо-скрипты, понаписанные ВМЕСТО нормальной системы мониторинга, отправят в Prometheus или Graphite метрики - кто их смотреть будет и как использовать? Не может же админ повесить себе в лучшем случае десяток тысяч графиков - и на все смотреть, не отрываясь, дабы что-нибудь важное не пропустить?

Видимо, для того же Graphite данные должна чудесным образом собирать некая внешняя система мониторинга, а Graphite должен по сути только предоставлять быстрый доступ к историческим данным?

Для мониторинга работы хитроумного местечкового самописного приклада вещи типа Graphite, может, и подходят (всё равно же мониторинг по существу костыльный: ни у кого нет времени делать нормальный внешний мониторинг своих приложений - perf_counter'ы, SNMP, WMI, каждый раз приходится ковырять чёрный ящик снаружи), но я что-то совсем не врубаюсь, а как это для мониторинга инфраструктуры заюзать?

P.S. Конкретно для Zabbix'а начиная с 3-й версии можно написать на Си плагин, сгружающий историческое барахло не в РСУБД, а в те же тайм-серии: это пока для меня единственное очевидное применение даже не Graphite, а всего одной его компоненты.

 ,

DRVTiny
()

fork() и возможность шарить уже выделенные страницы памяти

Форум — Development

Возможно ли после fork'а расшарить между процессами выделенные процессу ДО fork'а участки памяти?

С моей тчоки зрения, это было бы разумным дополнением к Copy On Write стратегии: помимо концепции «копирования при необходимости» должна быть стратегия «совместно используемых участков памяти».

Это бы в корне отличалось от IPC Shared Memory, поскольку последняя system-wide и должна выделяться специально обученными методами, а тут - мы просто имеем дело с куском памяти, совместно используемым мастер-процессом и его потомками.

Где-то как это реализовано, я говорю о том, что всегда было и самоочевидно или же «я опять хочу невозможного»?

 ,

DRVTiny
()

Удобная упаковка/распаковка бинарных форматов по описанию?

Форум — Development

Нужно, чтобы по описанию структуры данных в духе: «поле hostid - целое 32 бита, поле trigger_value - целое беззнаковое один байт, поле groups - вектор из целых беззнаковых 32-х битных, поле description - строка в C-стиле, терминированная нулевым байтом» - можно было передавать в функцию запаковки структуру и получать на выходе компактное бинарное представление, ну и наоборот - совать компактное бинарное представление в функцию распаковки и получать на выходе структуру.

Суть в том, что BJSON'ы и CBOR'ы не подходят, поскольку хранят названия поле. Нужен вариант простой бинарной упаковки, когда назначение поля определяется порядком расположения его в бинарном представлении («первым идёт поле hostid, вторым - поле trigger_value, третьим - ... etc»).

Может, кто сталкивался с подобным готовым пакетом, а то колхозить не хочется.

 , ,

DRVTiny
()

Язык, активно использующий IPC Shared Memory без плясок с бубном?

Форум — Development

В заголовке - весь вопрос :)

Мне хотелось бы (как всегда невозможного?):

а) Не использовать файлы в любом виде для передачи данных между процессами

б) Не использовать MQ, in memory NoSQL, ... etc, etc

в) Использовать просто переменные языка, фактически находящиеся в shared memory и защищаемые mutex/semaphor'ами

г) Желательно, чтобы программа на языке «автомагически» умела чистить за собой созданные ею shared memory segment'ы при завершении дерева порождённых ею процессов. Возможно, стоит это делать в рамках cgroup'ы, но это уже досужие домыслы

Но главный вопрос всё-таки в том, умеет ли какой-либо язык программирования безо всяких явных сериализаций/десериализаций хранить в Shared Memory свои переменные?

Заранее сурово признателен! :)

 , ,

DRVTiny
()

Event Loop'ы в Perl - это...

Форум — Development

кооперативная многозадачность в рамках одного процесса.

Это значит, что в рамках одного процесса:

1) Пока один асинхронный обработчик не завершится - другой не запустится;

2) Факт наступления нового события выявляется исключительно между запуском асинхронных обработчиков, время выполнения которых в худшем случае может быть непредсказуемым. Это значит, что если событие требует реакции от приложения за разумное время (пример: подключение на сокет) - его можно и прошляпить ненароком;

3) «Зато» в асинхронном обработчике A0 невозбранно можно пользоваться любыми глобальными переменными (до первого асинхронного вызова A1 внутри данного А0 - даже если A0 блокируется в ожидании результатов A1) и вообще мало задумываться о том, что приложение не вполне последовательно выполняется.

Я почитал доки по libev, ну и в целом не первый год пишу код с использованием AnyEvent+EV и Mojolicious (на самом деле те же AnyEvent+EV) - вроде всё так и есть...

Прошу поправить/опровергнуть меня и/или дополнить. Спасибо!

 , ev,

DRVTiny
()

Академические алгоритмы в современном программировании: не маразм ли?

Форум — Talks

У меня складывается стойкое ощущение, что использование классических супер-эффективных алгоритмов со всякими чудесными O(n) в современных реалиях, когда серверы со 128-ю процессорными ядрами стали скорее нормой, чем роскошью - в общем, это похоже на маразматическое ретроградство и заскорузлость мозга в принципиальном нежелании критически оценивать свои «бесценные» университетские знания, полученные от людей, не всегда догадывающихся о существовании многопоточности.

На мой взгляд, в современных реалиях наиболее эффективно себя показывают алгоритмы «разделяй и властвуй» наподобие QuickSort'а - т.е. те алгоритмы, которые позволяют разбить выполнение задачи на множество параллельно выполняющихся подзадач. А программистов, не задумывающихся о распараллеливании, синхронизации и склейке результатов - нужно гнать из профессии ссаными тряпками, сколько бы ни было у них гонора в связи с тем, что они всего Кнута выучили наизусть.

Это сугубо моё мнение, которое никому не навязываю, зато предлагаю открытую дискуссию.

 , , ,

DRVTiny
()

Проект-ответвление Perl 5: помогите вспомнить

Форум — Development

Несколько раз наталкивался на проект, по сути являющимся ограниченно совместимым с Perl 5 языком, но умеющим компилироваться в машинный код.

В силу у(щербнос)ти реализации всего, что касается потоков, в оригинальном Perl, очень интересно было бы попробовать тот проект - если код компилируется, то никакого гомосексуализма с «тредами интерпретатора» там быть не должно. Ну а в степени замороченности кода на Perl можно и подвинуться чуток. К тому же, я точно помню, что в том проекте было заявлено, что за счёт оптимизаций perl-код там работает существенно быстрее.

В общем, помогите найти это чудо, пожалуйста! То ли я как-то не так ищу, то ли ещё что, но у меня найти его не получается :(

Спасибо!

 ,

DRVTiny
()

Самые быстрые способы массовой записи в Redis и массового чтения из Redis

Форум — Development

Предлагаю помериться таймингами и сравнить эффективность алгоритмов записи/чтения применительно к Redis и языку Perl

Задача следующая:

Сначала как можно быстрее записать в пустую базу Redis N объектов (N для отсечки 2000 штук), а потом как можно быстрее их оттуда считать.

Объекты должны быть хешами, содержащими 2 поля: 1 текстовое поле длиной до 15-ти символов и одно числовое поле, содержащее произвольное число от 0 до N-1.

Для записи и чтения можно использовать разные пакеты Perl.

Интересно выяснить, какой модуль для работы с Redis в Perl быстрее всех и какая техника записи/чтения самая эффективная. Я уже делал подобный тест, но вполне вероятно, что мой путь его выполнения был неоптимальным.

P.S. Если есть желание, можно для сравнения накатать тесты и на других ___интерпретируемых___ языках программирования.

 ,

DRVTiny
()

Какой системой мониторинга пользуетесь?

Голосования — Голосования

Опрос для тех, кто всё-таки какой-либо СМ пользуется, посему варианта «Не пользуюсь» здесь и не предусмотрено (иначе он просто испортит статистику).

  1. Zabbix 273 (63%)

    ********************************************************************************************************************************************************************************************************************************************************************************************************************************

  2. Nagios (и его клоны) 97 (22%)

    *****************************************************************************************************************

  3. Другая OpenSource СМ 52 (12%)

    ************************************************************

  4. Munin 44 (10%)

    ***************************************************

  5. Cacti 35 (8%)

    *****************************************

  6. Другая проприетарная СМ 31 (7%)

    ************************************

  7. Prometheus 25 (6%)

    *****************************

  8. Microsoft SCOM 10 (2%)

    ***********

  9. ZenOSS 9 (2%)

    **********

  10. OpenNMS 9 (2%)

    **********

  11. NetXMS 9 (2%)

    **********

  12. IBM Tivoli Monitoring 8 (2%)

    *********

  13. HP OpenView 8 (2%)

    *********

Всего голосов: 610, всего проголосовавших: 432

 , ,

DRVTiny
()

Как правильно вызвать оригинальный метод родителя из потомка?

Форум — Development

Хочу переопределить метод send класса Zabbix::Sender (наследующего Moose::Object'у). Делаю так, и оно так работает:

#!/usr/bin/perl
package Zabbix::Sender::Clever;
use 5.16.1;
use Moose;
extends 'Zabbix::Sender';

has 'debug' => (
    'is'    => 'rw',
    'isa'   => 'Bool',
    'default' => 0,
);

has 'dryrun' => (
    'is'    => 'rw',
    'isa'   => 'Bool',
    'default' => 0,
);
         
sub send {
  my $self=shift;
  my $item={'key'=>$_[0],'val'=>$_[1]};
  printf STDERR "Feeding item <<%s>> on host <<%s>> with value <<%s>>\n", $item->{'key'}, $self->hostname, $item->{'val'} if $self->debug;
  unless ($self->dryrun) {
    Zabbix::Sender::send($self, @_);
    say 'INFO: '.$self->_info;
  }
  
}

package main;
my $z=Zabbix::Sender::Clever->new('server'=>'localhost');
$z->dryrun(0);
$z->debug(1);

$z->send('item.key','hello');

Но... Сугубо ИМХО это как-то немного уродливо смотрится вызов метода родителя «Zabbix::Sender::send($self, @_);». В конце-концов внутри меодов наследующего я хотя могу забыть о конкретном имени класса родителя и написать хотя бы просто __PARENT__::send($self) ?

А в идеале хотелось бы чего-то вроде $self->PARENT->send();

Есть ли такие красивости в Moose? Что-то не нашёл...

 , ,

DRVTiny
()

Патчи на методы класса/объекта или «есть ли в природе рантайм-дебагеры»

Форум — Development

Хотелось бы что-то вроде такого:

«После того, как неинициализированной переменной $a будет присвоено значение, вызвать вот такой метод объекта».

Поясню смысл:

Я могу наследовать объект, это прекрасно.

Я могу всячески переопределять его методы и свойства, даже ломая всю логику исходного объекта, которому наследую... Ну, положим, это менее прекрасно.

Но ещё я чаще всего не хочу в принципе ничего модифицировать глобально в самом объекте, а хочу, например, знать, что у него там в кишках происходит. Ну, например, совершенно классический случай: исходно данный объект очень скупо логирует происходящее, а мне бы хотелось, чтобы он при несовпадении фазы луны и цвета большой медведицы - всё-таки что-нибудь полезное капнул мне в лог.

Мне, конечно, хотелось бы вставить внутрь такого объекта breakpoint, но... а что если протоколируемая ситуация происходит только в рантайме при невыясненных обстоятельствах? Или что если объект всячески использует обработчики событий, распараллеливание и пр. - и тоже интересная ситуация ни в каком дебагере не вылезает никогда, а вот в рантайме - вполне, и самым неприятным образом.

Т.е. я бы хотел просто наложить некий патч на метод объекта, объяснив языку программирования тем или иным образом: после того, как в методе объекта происходит вот это или даже до того, как происходит вон то - вставь-ка ты мне небольшой кусочек кода, ну или хотя бы вызови добавленный мной при наследовании метод класса.

Почему это нужно? Почему нельзя просто переопределить метод после наследования?

Ответ простой: логика метода, как правило, не сильно меняется с течением времени, глобальный рефакторинг случается редко, и его легко заметить - поэтому достаточно высокоуровневое описание патча в духе «после инициализации переменной, сделай это» - переживёт обновления исходного класса с высокой долей вероятности. В конце-концов проблему несовместимости «патча» выявит как таковой «патчер» в языке - и либо просто не выполнит соотв. кусок кода, выдав при запуске ошибку (если проблема определяется на этапе компиляции), либо вывалит error в рантайме - плохо конечно, но для того и нужны регрессионные автотесты, чтобы предупреждать заранее подобные казусы. А вот если я переопределяю сам метод, исходно сделав тупо копипасту - то мне волей-не волей придётся потом следить за всеми «мутациями» кода класса, обновляя копипасту... и это как бы при том, что я НЕ являюсь его мейнтейнером (а может быть и не знаю его мейнтейнера)!

Хорошо, когда описанное можно сделать before или after hook'ом (например, в Perl5/Moose такие штуки есть), но плохо, когда в общем случае нужно всё-таки пропатчить объект в произвольном месте.

Вот как? Есть ли уже какие-то решения данной задачи? Насколько я отстал от жизни или почему мне не нужно то, что мне нужно?

Просветите, пожалуйста!

P.S.

Кстати, да, было бы ещё интересно не модифицировать класс, но модицифировать именно методы уже созданных инстансов класса, объектов то бишь. Ибо объектов 100500 штук и какие-то из них я хочу патчить, а какие-то - совершенно не хочу, даром не надо.

 , , ,

DRVTiny
()

Тесты с Selenium 3 под Linux

Форум — Web-development

Я что-то уже изрядно устал пытаться это настроить. Хоть у кого-нибудь получалось?

Суть в том, что есть виртуалка под CentOS 7, есть firefox, Xvfb и все-все-все. При этом непонятно, как в принципе запустить тест на каком-нибудь perl или php под это всё хозяйство.

Настраивал так: http://chandrewz.github.io/blog/selenium-on-centos

Код на Perl такой:

use strict;
use warnings;
use 5.16.1;
use utf8;

use WWW::Selenium;

    my $sel = WWW::Selenium->new( host => "localhost",
                                  port => 4444,
                                  browser => "*firefox",
                                  browser_url => "http://intranet-site.com",
                                );

    $sel->start;
    $sel->open("http://intranet-site.com");
    $sel->type("q", "hello world");
    $sel->click("btnG");
    $sel->wait_for_page_to_load(5000);
    print $sel->get_title;
    $sel->stop;

В результате выполнения теста получаю HTML-страницу, говорящую мне о том, что «нечто пошло не так» - без малейших уточнений на тему того, что именно не так.

Захожу на http://my-server:4444/wd/hub , пытаюсь «Create session» -> (выбор браузера) Firefox

selenim-server-3.0.1 в консоли сообщает мне «красивыми» exception'ами, что geckodriver не установлен и даже даёт ссылку на github, откуда это чудо ставить.

Теперь проблема: во-первых, в статье http://chandrewz.github.io/blog/selenium-on-centos ничего про какой-то geckodriver не написано. Во-вторых я распаковываю geckodriver, захожу в src/ - а там что-то совершенно непонятное, и как это использовать - одним разработчикам известно наверное (ну, может, ещё здесь кто в курсе).

Я в недоумении... Готов писать не обязательно на Perl'е, можно на PHP, суть не в этом. Суть в том, что из документации по Selenium вообще непонятно, «how to get started» в моём случае. Очень много буков, очень много совершенно меня не касающегося текста - и нет простого мануала, как сделать так, чтобы это заработало не на Windows и при этом клиентский код был не на Java :(

Жесть просто. Помогите разобраться, пожалуйста!

P.S. Ошибка в виде портянки из HTML при запуске моего куска кода:

Error requesting http://localhost:4444/selenium-server/driver/:
<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <link rel="stylesheet" type="text/css" href="/assets/displayhelpservlet.css" media="all"/>
  <script src="/assets/jquery-1.6.1.min.js" type="text/javascript"></script>
  <script src="/assets/displayhelpservlet.js" type="text/javascript"></script>
  <script type="text/javascript">
    var json = Object.freeze('{"version":"3.0.1","type":"Standalone","consoleLink":"/wd/hub"}');
  </script>
</head>
<body>

<div id="content">
  <div id="help-heading">
    <h1><span id="logo"></span></h1>
    <h2>Selenium <span class="se-type"></span>&nbsp;v.<span class="se-version"></span></h2>
  </div>

  <div id="content-body">
    <p>
      Whoops! The URL specified routes to this help page.
    </p>
    <p>
      For more information about Selenium <span class="se-type"></span> please see the
      <a class="se-docs">docs</a> and/or visit the <a class="se-wiki">wiki</a>.
      <span id="console-item">
        Or perhaps you are looking for the Selenium <span class="se-type"></span> <a class="se-console">console</a>.
      </span>
    </p>
    <p>
      Happy Testing!
    </p>
  </div>

  <div>
    <footer id="help-footer">
      Selenium is made possible through the efforts of our open source community, contributions from
      these <a href="https://github.com/SeleniumHQ/selenium/blob/master/AUTHORS">people</a>, and our
      <a href="http://www.seleniumhq.org/sponsors/">sponsors</a>.
   </footer>
  </div>
 </div>

</body>
</html>

 , web testing

DRVTiny
()

Элегантный способ генерации последовательности для чтения массива порциями

Форум — Development

Хочется сделать рефакторинг пис-оф-кода.

Нужно для массива длиной в M элементов получить в другом массиве пары чисел, позволяющие считать первый массив равными порциями «по частям».

См. код ниже. Здесь $m - это количество элементов в массиве. $c - это размер порции для считывания.

Я это делаю сейчас так:

use Data::Dumper;
my $m=90;
my $c=15;
my @seq=map { 
 my $t1=$_*$c;
 my $t2=$t1+$c-1;
 $t2>($m-1)?$t1==$m?():[$t1=>$m-1]:[$t1=>$t2]
} 0..int($m/$c);
print Dumper \@seq

На выходе получаю массив @seq:

$VAR1 = [
          [
            0,
            14
          ],
          [
            15,
            29
          ],
          [
            30,
            44
          ],
          [
            45,
            59
          ],
          [
            60,
            74
          ],
          [
            75,
            89
          ]
        ];

Внимание, вопрос: как сделать то же самое:

а) Быстрее

б) Экономичнее

в) Лаконичнее

?

Например, использование splice не отвечает требованиям «быстрее» и «экономичнее», хотя удовлетворяет «лаконичнее».

Предыдущая часть мучений на ту же тему: «Разделяй и властвуй»: как обрабатывать списки «порциями»

 ,

DRVTiny
()

RSS подписка на новые темы