Ни разу не постил на Хабр, а тут такой интересный повод нарисовался.

Вопросы, обсуждаемые в статье:

  • Выбрать публичность или приватность — вот в чем вопрос;
  • Кто главнее — клиент или сервер?
  • Прочтите статью и вы увидите, как на эти вопрос отвечает 1С в своей платформе;
  • И еще неожиданный интересный факт о Google узнают те, кто дочитает до конца;
  • Я кратко расскажу, как я нашел точного виновника бага.

Сразу скажу, что я любитель находить баги, а баги любят находить меня. И 13 число в моей жизни играет не последнюю роль.

История


Итак, сижу я вечером (на дворе как раз 13 декабря), тружусь над одним из своих любимых продуктов xUnitFor1C над значимым релизом 4.0

Тестирую работу тестов в режиме управляемого приложения при переходе с клиента на сервер и обратно.

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

В модуле контекста ядра тестирования (Упр.форма) созданы 2 похожих метода ВыполнитьТестовыйМетодНаКлиенте (признак &НаКлиенте) и ВыполнитьТестовыйМетодНаСервере (признак &НаСервере).
Назначение их понятно из названия.

Обычно в тесте я использовал метод УпрФорма.ВыполнитьТестовыйМетодНаКлиенте для проверки тестов УФ, т.е. через контекст управляемой формы.

Все штатно, проблем нет.

Но теперь мне понадобилось проверить переход с клиента на сервер. Я решил, что хватит использовать ВыполнитьТестовыйМетодНаКлиенте, пора заняться более глубоким хакингом и вызвал метод ВыполнитьТестовыйМетодНаСервере.

Написал специальный тест, описал поведение согласно сценария и внутри теста вызываю ЭтаФорма.ВыполнитьТестовыйМетодНаСервере.

Тест предсказуемо падает, ведь я работаю по методике TDD. Начинаю разбираться, что нужно поправить в коде, чтобы тест заработал (ТДД работает именно так).

Проходит несколько минут, и я с огромным изумлением вижу, что вызываемой мной метод ВыполнитьТестовыйМетодНаСервере является приватным, т.е. у него нет признака Экспорт!

При этом я его успешно вызываю, и он прекрасно отрабатывает.

Поиск и подтверждение бага в платформе 1С


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

Сначала я проверил, вызываю я правильный код из правильного места и т.д. Еще через пару минут я убедился, что ошибки нет, действительно, я вызываю приватный метод и он успешно отрабатывает!

Также я проверил, что метод ВыполнитьТестовыйМетодНаКлиенте является публичным/экспортным методом.




Согласно методикам поиска багов я максимально упростил ситуацию и исключил сторонние факторы:

создал отдельную внешнюю обработку. Добавил к ней простую управляемую форму.
Добавил 2 команды ВызовПриватногоКлиентскогоМетода и ВызовПриватногоСерверногоМетода
Для этой формы добавил следующий код:

&НаСервере
Процедура ПриватнаяНаСервере()
  Сообщить("ПриватнаяНаСервере");
  Сообщить("После вызова ПриватнаяНаСервере");
КонецПроцедуры

&НаКлиенте
Процедура ВызовПриватногоСерверногоМетода(Команда)
  ЭтаФорма.ПриватнаяНаСервере(); // не выдает ошибку !!
КонецПроцедуры

&НаКлиенте
Процедура ПриватнаяНаКлиенте()
  Сообщить("ПриватнаяНаКлиенте");
КонецПроцедуры

&НаКлиенте
Процедура ВызовПриватногоКлиентскогоМетода(Команда)
  ЭтаФорма.ПриватнаяНаКлиенте(); // как и положено, выдает исключение
  Сообщить("После вызова ПриватнаяНаКлиенте"); 
КонецПроцедуры


Первоначально я запускал подобный ручной тест на свежайшей версии 8.3.7.1805 (выпущена 10.12.2015, если я не ошибаюсь).

Получаю поведение:
  • приватный серверный метод успешно вызывается, сообщения отрабатывают. Это ошибка.
  • с приватным клиентским методом проще. Выдается правильное исключение, что метод не обнаружен.
    {Форма.Форма.Форма(15)}: Метод объекта не обнаружен (ПриватнаяНаКлиенте)
    ЭтаФорма.ПриватнаяНаКлиенте();

В итоге получаем явный баг в 8.3.7.

Далее я согласно тем же методикам поиска багов проверяю поведение на другой платформе 1С 8.2.19
Поведение абсолютно такое же.

Проверил поведение на встроенной обработке, те же проблемы.

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




Риторические вопросы


  • Получается, это не баг, это фича, потому что подобное «странное» поведение наблюдается очень давно, уже несколько лет?
  • А как же приватность/публичность? это же базовые принципы!
  • А как же инкапсуляция? получается, что кто угодно может вызвать скрытые серверные методы и нарушить поведение.
  • А как же равноправие? почему клиент настолько ущемлен по сравнению с сервером :) ?


В итоге этот баг сделал мой вечер!

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

Ух, как теперь можно развернуться кодерам на языке 1С, теперь можно экспорт не писать, все и без него работает.
Это же сколько кода можно наваять, если не тратить время на написание Экспорт! А в масштабах страны какая экономия времени?

А если более серьезно, то хочется обратиться к 1С для исправления данной ошибки.
Евангелист 1С PeterG, что скажешь?
Также предлагаю встроить в продукт АПК (Автоматизированная проверка конфигурации) проверку на подобный баг.


PS Если кому-то нужно, могу дать обработку для ручного тестирования.

PPS А если кому интересно, что же нового будет в версии 4.0 xUnitFor1C, ждите следующей статьи и новогоднего подарка!

А причем здесь Google?
PPPS при поиске картинки для статьи обнаружил, что при поиске картинок в Гугл для фразы «нарушение приватности» больше всего картинок с логотипом именно Google. К чему бы это?

Комментарии (2)


  1. Melex
    15.12.2015 16:52
    +1

    Не понял позыв статьи.
    Вы работаете в контексте текущей формы, почему вам не должны быть доступны эти функции?
    Вот если бы вы могли вызывать таким образом приватные функции из другой формы, тогда я еще бы понял, этого дико не хватает при написании механизмов добавления строк в типовые документы, так как там все функции перерасчета — приватные.

    На проводки ничего не повлияет, так как проводки делаются непосредственно в самом модуле документа, а не его формы. Так что тут все чисто.

    В модуле контекста ядра тестирования (Упр.форма) созданы 2 похожих метода ВыполнитьТестовыйМетодНаКлиенте (признак &НаКлиенте) и ВыполнитьТестовыйМетодНаСервере (признак &НаСервере).
    

    Вот раньше, в 8.3.5 (вроде еще можно было), я мог создать две функции с одним именем, и в зависимости от контекста — я получал соответствующий вызов нужной функции, вот это было удобно, не надо было лепить кучу модулей Клиент, Сервер, КлиентСервер :) Но эту фичу починили :(


    1. artbear
      15.12.2015 18:02

      Нет, я работаю именно через контекст управляемой формы.
      У меня как раз все было хуже, т.к. вызов идет из другой формы — из формы раннера тестов вызываются методы другой управляемой формы.

      А здесь странность — почему приватные клиентские методы нельзя вызывать, а приватные серверные можно?