Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Несколько разных запросов к одному ресурсу #7

Closed
ivanych opened this issue Dec 8, 2015 · 39 comments
Assignees

Comments

@ivanych
Copy link

ivanych commented Dec 8, 2015

Как сделать несколько разных запросов к одному ресурсу? Например, два get-запроса с разными параметрами:

test.ru/resource?param=value1
test.ru/resource?param=value2

И тесты для разных запросов тоже разные.

@melezhik
Copy link
Owner

melezhik commented Dec 8, 2015

есть несколько способов. напрашивается использование swat модулей. вот как можно написать

# upstream story - основная история вызывающая downstream story - GET /resource
# название роута неприниципиально, т.к. запрос к серверу делаться не будет
#  а response заспуфится через set_response
# читайте далее в исходнике virtual/resource/hook.pm

$ cat virtual/resource/get.txt 
done

# upstream story hook
$ cat virtual/resource/hook.pm

# в хуке для основной истории - два раз вызываем downstream story  с разными значениями для параметра param:

call_swat_module( GET => '/resource', { value => 'value1' }  ); #  соответсвует test.ru/resource?param=value1

call_swat_module( GET => 'resource', { value => 'value2' }  ); #  соответсвует test.ru/resource?param=value2

# так это upstream story, то можно заспуфить ответ сервера, так как в САМОЙ в upstream истории запроса в  приложение не происходит, но swat требует, что бы был хоть какой-то ответ, который можно проверить

set_response('done');

# теперь опишем downstream story или swat module

$ cat resource/swat.ini
# объявляем историю модулем:
swat_module=1
curl_params='-G param=%value%'

cat resource/get.txt
200 OK

Подробнее про swat модули можно почитать здесь - https://github.com/melezhik/swat#upstream-and-downstream-stories

@melezhik melezhik self-assigned this Dec 8, 2015
@melezhik
Copy link
Owner

melezhik commented Dec 8, 2015

Да и соответственно , если хочется делать два разных запроса, нужно просто создать две upstream истории, внутри каждой из которых будет свой вызов ресурса GET /resource, например так:

# virtual/one/hook.pm
call_swat_module( GET => '/resource', { value => 'value1' }  );
set_response('done');

# virtual/two/hook.pm
call_swat_module( GET => '/resource', { value => 'value2' }  );
set_response('done');

@melezhik
Copy link
Owner

melezhik commented Dec 8, 2015

Второй вариант создать два роута, и воспользоваться функцией modify_resource. Он более простой для реализации, но более грубый:


# resource1/hook.pm
modify_resource(  sub {  '/resource?param=value1' } );

# resource2/hook.pm
modify_resource(  sub {  '/resource?param=value2' } );

Про функцию modify_resource написано здесь - https://github.com/melezhik/swat#redefine-http-resources

@melezhik
Copy link
Owner

melezhik commented Dec 9, 2015

Михаил , получились разобраться с этим ? Пишите , если помощь будет нужна.

@ivanych
Copy link
Author

ivanych commented Dec 9, 2015

Я еще не пробовал, ночь же была:)

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Сделал практически один в один как в первом комментарии (только run_swat_module). Но не пойму, как теперь для каждого запроса сделать свой набор тестов. Для обоих запросов вроде как запускается один и тот же набор тестов, из resource/get.txt, а мне надо разные тесты, ведь запросы с разными параметрами возвращают разные ответы.

Второй комментарий про virtual/one/hook.pm и virtual/two/hook.pm я не понял, вроде это ничем не отличается от двух вызовов модуля в одном virtual/resource/hook.pm, как в первом комментарии.

@melezhik
Copy link
Owner

т.е. хочется не только делать разные запросы ( GET '/resource?param=value1' , GET '/resource?param=value2' ), но и по-раному их валидировать ? так?

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Да, именно так.

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Вроде бы по логике должна быть возможность писать тесты в virtual/resource/hook.pm, а не в resource/get.txt. Можно так сделать?

@melezhik
Copy link
Owner

тогда немного перепишем первый вариант, реализацию resource/get.txt.
и будем использовать т.н. генераторы проверочных утверждений ( https://github.com/melezhik/outthentic-dsl#generators ) , например так:

$ cat resource/get.txt

# это всегда ведь так?
200 OK

# далее в зависимости от значение переменной value

generator: \ 
my $v = module_varibale('value'); \
my @list = ();  \

push @list, 'value1' if  $v eq 'value1' ; \
push @list, 'value2' if  $v eq 'value2' ; \
[ @list ] 

генератор можно потом будем убрать из get.txt выделить в обычную функцию ( назвать ее как нибудь там assert_for_value ) и написать компактнее:

$ cat resource/get.txt
generator:  assert_for_value(module_varibale('value'));

@melezhik
Copy link
Owner

Вроде бы по логике должна быть возможность писать тесты в virtual/resource/hook.pm, а не в resource/get.txt. Можно так сделать?

нет тесты ( проверочные утверждения ) всегда присываются в файлах http методов ( aka check list files ) - get.txt, post.txt и т.д , другой вопрос, что в самих хуках ты можешь определить функции - генераторы и вызвать их в файлах чек листов

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Как-то это нехорошо... параметры задаются в хаках, а проверяются в модулях. Т.е. пишу я новый хак - и нужно лезть править модуль. А если хак и модуль пишут разные люди?

@melezhik
Copy link
Owner

что бы было более понятнее можно с использованием хука написать так:

$ cat virtual/resource/hook.pm

call_swat_module( 
  GET => '/resource', 
  { 
    value => 'value1' ,
    check_f => sub { ['value1'] } 
  }  
); 

call_swat_module( 
   GET => 'resource', 
   { 
     value => 'value2' ,
     check_f => sub { ['value2'] } 
   }  
); 

set_response('done');

$ cat resource/get.txt
generator:  module_varibale('check_f')->()

@melezhik
Copy link
Owner

Как-то это нехорошо... параметры задаются в хуках, а проверяются в модулях. Т.е. пишу я новый хук - и нужно лезть править модуль. А если хук и модуль пишут разные люди?

Михаил, не очень понял последний вопрос, что именно смущает, можете переформулировать?

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Хм. Т.е. нужно вводить устное соглашение, что хук (читай - человек, пишущий хук) всегда определяет функцию с заранее оговоренным именем, или вот как выше, создает параметр типа check_f со ссылкой на функцию.

А в модуле эту функцию всегда вызывать.

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

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

Не думали так сделать? Или я ерунду говорю, не до конца разобравшись?

@melezhik
Copy link
Owner

Просто что бы было понимание:

  • Хук всегда относится к конкретной истории ( http запросу )
  • Одно из основых назначений хука - иметь возможность в контексте одного запроса ( истории ) вызывать другие запросы ( истории ) - перед запуском этого конкретного запроса.
  • Эти вызываемые истории - называются downstream stories или модули
  • История делающая вызов downstream story называется upstream story или главной историей
  • Модули также могут иметь параметры - задаваемые при вызове модуля в главной истории
  • Downstream истории никогда не будут вызываны swat напрмямую при парсинге дерева тестовых файлов, они всегда вызываются черех хук upstream истории, посредством функции run_swat_module()
  • Upstream stories - всегда вызываются swat напрямую при парсинге деоева тестов.
  • По умолчанию swat история считается upstream ( хотя это еще не означает что она будет вызывать какие-либо downstream истории ), если не указано swat_module=1 в настройках истории
  • Написание нового хука означает что в начале вы пишите новую историю и уже потом к ней хук, еще раз хук всегда определяется для конкрентной истрии , и никак не связан с тем что история явлется upstream или downstream, у каждой истории, вне зависимости от ее типа может быть определ хук.

Надеюсь это немного прояснило

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

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

Сейчас получается так, то модуль сам себе задает тесты. Но модуль же не знает, как и откуда он будет вызван, поэтому и тесты он не может задать адекватно. Предложенный Вами выше способ передачи ему тестов через ссылку на функцию, определенную в хуке, кажется мне обходным путем.

@melezhik
Copy link
Owner

Мне кажется, было бы удобнее сделать так, чтобы утверждения/тесты задавались в самом хуке, а не в модуле. Чтобы не нужно было гадать - вызовет ли модуль функцию из хука, или не вызовет... Чтобы всегда проверка задавалась там же, где задавались параметры. Не думали так сделать? Или я ерунду говорю, не до конца разобравшись?

Мне кажется я понимаю что вы говорите. Но дело в том, что архитектура такова что:

  • проверочные утверждения прописываются всегда в проверочных файлах ( чек лист файлы, они же файлы http методов ) - т.е. едниственное место где вы определяется проверочную логику
  • другой вопрос, что swat DSL повзоволяет использовать уже кем-то написанные проверочные утвержения посредством механизма генераторов , таким образом всгда можно написать проверочное утверждение где-то еще ввиде функции возвращающей ссылку на массив строк ( не только внутри проверочного файла - быстрый режим разработки "in place" ) - например внутри хука или внтури обычного perl модуля добавляемо по зависимости или лежащего внутри project_root/lib/Foo/Bar.pm - и затем использовать данное проверное утверждение внутри проверочного файла:
   generator: my_cool_check();

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Я предлагаю сделать байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука.

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Проблема текущей архитектуры в том, что сейчас проверочный файл не знает, где взять уже кем-то написанные проверочные утвержения и есть ли они вообще. Для этого требуется устная договоренность с другими разработчиками, что они будут писать проверочные утверждения и будут называть их оговоренными именами.

@melezhik
Copy link
Owner

Сейчас получается так, то модуль сам себе задает тесты.

Модуль определяет интерфейс и частичную реализацию.
Частичная реализация - проверочные утвеждения, определенные внутри проверончого файла модуля:

cat  foo/bar/get.txt
 200 OK
base_check

Интерфейс - это вызовы вншних проверочных утверждений через генераторы. Внешние проверочные утверждения должны быть определены где-то.

вариации на тему:

cat  foo/bar/get.txt

# external_generator() should be defined somewhere else
generator : external_generator()

#  module_variable('external_generator_array') is ARRAYRE
generator : module_variable('external_generator_array')

#  module_variable('external_generator_f') is CODEREF
generator : module_variable('external_generator_f')->()

@melezhik
Copy link
Owner

Я предлагаю сделай байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука.

они могут оттуда браться, но могу браться как и самого проверочного файла модуля так и и из
upstream истории ( варианты я привел ).

@melezhik
Copy link
Owner

Проблема текущей архитектуры в том, что сейчас проверочный файл не знает, где взять уже кем-то написанные проверочные утвержения и есть ли они вообще. Для этого требуется устная договоренность с другими разработчиками, что они будут писать проверочные утверждения и будут называть их оговоренными именами.

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

Если хочется распределить разработку в варианте на который указываете вы, а именно

  • кто-то пишет склет сват тестов
  • кто-то пишет проверочные утвержения ввиде обычных perl модулей и функций

это возможно и вполне валидно, но даже в этом случае не вижу никаких проблем.

Автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API, автор сват тестов использую эту информацию использует эти утвеждения

Да и мне кажется я догадался к чему вы клонили. Дело в том swat модули являются повторно используемыми только в рамках одного тестового набора (swat проекта) - и не предполагается что они будут использовать кем-то еще в других swat проектах

@melezhik
Copy link
Owner

Т.е. мой основной посыл наверное такой.

Проверочные файлы могут декларировать некий интерфейс для реализации ( вызов внешних проверочных утверждений ). Т.е. я себе с трудом представляю когда кто-то создает проверочный файл в котором существует вызовы внешних проверочных утверждений о которых никто не знает. Как правило, эти внешние проверочные утверждения либо УЖЕ кем-то реализованы - как cpan, perl модули ( см. мой предыдущий пример ) ввиде внешних библиотек, либо ОБЯЗАНЫ быть определены где-то еще внутри проетка и это не тайное знание, т.к. скорее всего тот же кто создает данный проверочный файл , тот же и будет реализовывать внешние проверочные утверждения.

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

@melezhik
Copy link
Owner

Хм. Т.е. нужно вводить устное соглашение, что хук (читай - человек, пишущий хук) всегда определяет функцию с заранее оговоренным именем, или вот как выше, создает параметр типа check_f со ссылкой на функцию. А в модуле эту функцию всегда вызывать.

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

@melezhik
Copy link
Owner

Я предлагаю сделать байпас - если история является модулем, то утверждения для нее берутся не из файла методов, а из вызвавшего хука

Swat позволяет далать как угодно и в том числе так. Не вижу смысла форсировать такое поведение. Если кому-то нужно он может написать модуль с базовами / дефолтными определениями проверочных утверждений, которые затем можно будет переопределить извне, при вызове данного модуля:

# хук модуля
cat  bar/baz/hook.pm

sub baz_check {
 return [ module_variable('baz_check') ? module_variable('baz_check')->() : 'baz_check' ]
}

# проверочный файл
# cat bar/baz/get.txt

 generator: baz_check();

# хук основной истории
# переопределяем baz_check

run_swat_module(
   GET => 'bar/baz/',
   {
       baz_check => sub {  'ANOTHER_BAZ_CHECK' }
   }
)

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

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

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

Автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API

Это бардак же. Это получается самопальное API поверх API свата. Два разработчика договорятся называть функцию check, а другие два разработчика - test, потом они поменяются местами и при написании новых тестов будут гадать, почему функция в хуке называется check, а из модуля вызывается test.

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

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

Да как же? Именно так всё и должно быть - модуль должен реализовать интерфейс ресурса, а параметры и результаты он проверять не должен, параметры и проверки задает совершенно другой человек, в хуке. Модуль не может знать, какие значения придут в параметрах, и модуль не может знать, какие ответы соответствуют этим параметрам.

Модуль должен просто вызвать функцию проверки из хука.

Собственно, это сейчас и происходит. Вопрос только в том, что имя этой функции сейчас предлагается оговаривать дополнительно, за рамками документации к свату. А я предлагаю задать это имя жестко, и модуль всегда должен вызывать эту функцию из вызвавшего его хука. Более того, если в хуке эта функция определена, то она должна переопределять тесты, заданные в самом модуле, чтобы не возникало конфликтов.

P.S. это всё в рамках одного проекта, я не говорю об использовании сват-модулей в других проектах.

@melezhik
Copy link
Owner

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

Вы видимо меня неправильно поняли. Архитектура swat не противоречет командой разработки кода. Просто в данном конкретном вопросе модуль не является повторно используемой единицей когда ВНЕ своего проекта. Пусть над проектом работает хоть 5 человек, но тот кто создал модуль просто напросто должен обеспечить что бы все внешние проверочные утвержения были реализованы, в частном случае - это сделает сам же автор модуля , но даже если он захочет передать "данный" модуль другим разработчикам он обязан как-то задекларировать требуемый к реализации интерфейс, устно или формально через докуменатацию это уже другой вопрос ... Не вижу с этим никаких проблем.

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Просто в данном конкретном вопросе модуль не является повторно используемой единицей когда ВНЕ своего проекта.

Это понятно.

он обязан как-то задекларировать требуемый к реализации интерфейс

Но это можно упростить и повысить надежность - просто задекларировав это на уровне самого свата.

@melezhik
Copy link
Owner

Это бардак же. Это получается самопальное API поверх API свата. Два разработчика договорятся называть функцию check, а другие два разработчика - test, потом они поменяются местами и при написании новых тестов будут гадать, почему функция в хуке называется check, а из модуля вызывается test.

Не очень понял утвердение про "самопальное API поверх API свата"
API swat и "API" модуля две совершенно разные вещи. По поводу бардка - мой предыдущий комментарий, не очень понимаю.

Под фразой автор "библиотеки" проверочных утверждений предоставляет информацию о рубличном API - я имел ввиду именно библиотеку разработанную вне какого-то модуля. Например можно представить себе набор регэксповых выражений для валидации строк с датами, такой набор регэксп выражений можно выразить ввиде функций, используемых в проверочных файлах swat. Ни какому конкретному модулю эти функции не относятся. Вот имменно таком случае эту библиотеку безопасно сипользовать в разных swat проектах, т.к. она никоем образом не зависит от их структуры и никак не связана с конретными сват модулями. А вот связка функций ( реализующий проверочные утверждения ) для конкрентного модуля о которой я упомянул в предыдущей комметарии - совершенно другое дело - такие функции наружу в другие сват проекты никто выставлять не собиратеся

@melezhik
Copy link
Owner

Но это можно упростить и повысить надежность - просто задекларировав это на уровне самого свата.

Согласен. Как идея принимается. Не уверен что это легко реализовать. Но суть вашего посыла ясна. Будем подумать ...

@melezhik
Copy link
Owner

Да как же? Именно так всё и должно быть - модуль должен реализовать интерфейс ресурса, а параметры и результаты он проверять не должен, параметры и проверки задает совершенно другой человек, в хуке. Модуль не может знать, какие значения придут в параметрах, и модуль не может знать, какие ответы соответствуют этим параметрам.

Ок. Модуль:

  • реализует http запрос
  • определяет скелет проверочной логики вернувшегося ответа
  • в данном скелете могут использоваться локальные проверочные утвереждения определенные по месту как есть (200 OK, generator: ["FOO", "BAR"] и так далее )
  • а могут быть вызовы внешних функкций, причем при этом могут использоваться параметры модуля ( переменные модуля если следовать сват терминологии ) - для получения внешних проверочных утвержений
  • таким образом скелет проверочной логики модуля может быть расширен , переопределен за счет внешних проверочных утверждений ( через механизм генераторов ) и/или через параметры модуля . Да кстати этот пункт применим и к обычной НЕ модульной истории, только без использования модульных переменных, их у upstream story просто нет, by design
  • возможность расширения модуля обеспечивает гибкость, но в тоже время соглашусь с вашими опасения уменьшает прозрачность и надежность когда ( что будет если данное внешнее проверочное утверждение не будет реализовано ? - сейчас получаем пространный стэк трейс от перла в рантайме )
  • но до дех пор пока сват модуль живет в рамках одного проекта - можно не очень переживать о потенциальных проблемах свзязанных с неправильным использованием swat модулей
  • хотя, как вы уже сказали - валидация на уровне сват таких проблем была бы очень полезна ... соглашусь

@melezhik
Copy link
Owner

Модуль должен просто вызвать функцию проверки из хука. Собственно, это сейчас и происходит. Вопрос только в том, что имя этой функции сейчас предлагается оговаривать дополнительно, за рамками документации к свату. А я предлагаю задать это имя жестко, и модуль всегда должен вызывать эту функцию из вызвавшего его хука. Более того, если в хуке эта функция определена, то она должна переопределять тесты, заданные в самом модуле, чтобы не возникало конфликтов.

Ок. Сейчас уже больше понимания о чем вы говорите ;-) вы предлагаете сделать обязательным реализацию интерфейса модуля на стороне вызвающего кода, в данном случае хука основной истории, и валидировать выполнение этого требования средствами сват. Эта интересная идея. Я подумаю ...

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Оке, кажется, договорились:)

@melezhik
Copy link
Owner

Да уж :) . Но пока юзайте в таком виде. Вариантов предостаточно. Над вашей идей надо еще думать ... По первоначальной проблеме ( Несколько разных запросов к одному ресурсу ) вопросы еще есть у вас?

@ivanych
Copy link
Author

ivanych commented Dec 10, 2015

Да, с исходным вопросом всё ясно, я уже сделал, работает, спасибо.

@melezhik
Copy link
Owner

Да, Михаил, я насчет интерфейса модулей думаю создам отдельный тикет . А мне интересно, если не секрет, какой на воде код тестов получается? можно вывести, ну по крайней мере ту часть, которую можно ))

@melezhik
Copy link
Owner

здесь все

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants