Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 7 additions & 2 deletions src/ScriptEngine.HostedScript/DefaultEventProcessor.cs
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ This Source Code Form is subject to the terms of the
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
using OneScript.Contexts;
using OneScript.Exceptions;
using OneScript.Execution;
Expand Down Expand Up @@ -125,18 +126,22 @@ public void RemoveAllHandlers(IRuntimeContextInstance eventSource)
public void HandleEvent(IRuntimeContextInstance eventSource, string eventName, IValue[] eventArgs,
IBslProcess process)
{
HandlersList handlersLocalCopy;
Handler[] handlersLocalCopy;

lock (_subscriptionLock)
{

if (!_registeredHandlers.TryGetValue(eventSource, out var handlers))
return;

if (!handlers.TryGetValue(eventName, out handlersLocalCopy))
if (!handlers.TryGetValue(eventName, out var handlersList))
{
return;
}

// Копия: обработчики могут подписываться и отписываться во время события,
// в том числе из других потоков
handlersLocalCopy = handlersList.ToArray();
}

foreach (var handler in handlersLocalCopy)
Expand Down
99 changes: 99 additions & 0 deletions tests/events.os
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@
Перем юТест;
Перем СчетчикВызовов;
Перем ПараметрыВызова;
Перем ИсточникОдноразовогоОбработчика;
Перем СобытиеНачалось;
Перем ОтпуститьСобытие;

Функция ПолучитьСписокТестов(ЮнитТестирование) Экспорт

Expand All @@ -17,6 +20,8 @@
ВсеТесты.Добавить("ТестДолжен_ПроверитьПодпискуНаСобытиеВВидеВыражения");
ВсеТесты.Добавить("ТестДолжен_ПроверитьПодпискуСОбработчикомВВидеВыражения");
ВсеТесты.Добавить("ТестДолжен_ПроверитьЧтоУИсточникаМожетБытьНесколькоСобытий");
ВсеТесты.Добавить("ТестДолжен_ПроверитьОтпискуОбработчикаВоВремяСобытия");
ВсеТесты.Добавить("ТестДолжен_ПроверитьПодпискуВоВремяСобытийИзФоновогоЗадания");

Возврат ВсеТесты;

Expand Down Expand Up @@ -195,4 +200,98 @@

КонецПроцедуры

Процедура ОдноразовыйОбработчикСобытия(Параметр1, Параметр2) Экспорт

УдалитьОбработчик ИсточникОдноразовогоОбработчика.МоеСобытие, ЭтотОбъект.ОдноразовыйОбработчикСобытия;
ОбработчикСобытия(Параметр1, Параметр2);

КонецПроцедуры

Процедура ТестДолжен_ПроверитьОтпискуОбработчикаВоВремяСобытия() Экспорт

ИсточникОдноразовогоОбработчика = Новый ТестСобытий;
ДобавитьОбработчик ИсточникОдноразовогоОбработчика.МоеСобытие, ЭтотОбъект.ОдноразовыйОбработчикСобытия;
ДобавитьОбработчик ИсточникОдноразовогоОбработчика.МоеСобытие, ЭтотОбъект.ОбработчикСобытия;

МассивПараметров = Новый Массив;
МассивПараметров.Добавить("П1");
МассивПараметров.Добавить("П2");

// Обработчик, отписавшийся во время события, не мешает вызвать остальные
ИсточникОдноразовогоОбработчика.СгенерироватьСобытие("МоеСобытие", МассивПараметров);
юТест.ПроверитьРавенство(2, СчетчикВызовов);

ИсточникОдноразовогоОбработчика.СгенерироватьСобытие("МоеСобытие", МассивПараметров);
юТест.ПроверитьРавенство(3, СчетчикВызовов);

КонецПроцедуры

Процедура ВременныйОбработчикСобытия(Параметр1, Параметр2) Экспорт
ОбработчикСобытия(Параметр1, Параметр2);
КонецПроцедуры

Процедура ОбработчикСобытияСОжиданием(Параметр1, Параметр2) Экспорт

// Держит вызов события, пока основной поток меняет подписку
СобытиеНачалось = Истина;
Для Номер = 1 По 500 Цикл
Если ОтпуститьСобытие Тогда
Прервать;
КонецЕсли;
Приостановить(10);
КонецЦикла;

// Иначе подписка поменялась бы уже после вызова события, и тест ничего не проверил
Если Не ОтпуститьСобытие Тогда
ВызватьИсключение "Не дождались изменения подписки во время события";
КонецЕсли;

КонецПроцедуры
Comment thread
coderabbitai[bot] marked this conversation as resolved.

Процедура СгенерироватьСобытиеВЗадании(Источник) Экспорт

МассивПараметров = Новый Массив;
МассивПараметров.Добавить("П1");
МассивПараметров.Добавить("П2");

Источник.СгенерироватьСобытие("МоеСобытие", МассивПараметров);

КонецПроцедуры

Процедура ТестДолжен_ПроверитьПодпискуВоВремяСобытийИзФоновогоЗадания() Экспорт

СобытиеНачалось = Ложь;
ОтпуститьСобытие = Ложь;

Источник = Новый ТестСобытий;
ДобавитьОбработчик Источник.МоеСобытие, ЭтотОбъект.ОбработчикСобытияСОжиданием;
ДобавитьОбработчик Источник.МоеСобытие, ЭтотОбъект.ОбработчикСобытия;

Параметры = Новый Массив;
Параметры.Добавить(Источник);
Задание = ФоновыеЗадания.Выполнить(ЭтотОбъект, "СгенерироватьСобытиеВЗадании", Параметры);

НачалосьДоИзмененияПодписки = Ложь;
Для Номер = 1 По 500 Цикл
Если СобытиеНачалось Тогда
НачалосьДоИзмененияПодписки = Истина;
Прервать;
КонецЕсли;
Приостановить(10);
КонецЦикла;

// Событие еще вызывается в задании: подписка меняется посреди перебора обработчиков
ДобавитьОбработчик Источник.МоеСобытие, ЭтотОбъект.ВременныйОбработчикСобытия;
УдалитьОбработчик Источник.МоеСобытие, ЭтотОбъект.ВременныйОбработчикСобытия;
ОтпуститьСобытие = Истина;
Задание.ОжидатьЗавершения();

юТест.ПроверитьИстину(НачалосьДоИзмененияПодписки, "Событие должно было начаться до изменения подписки");
Если Задание.ИнформацияОбОшибке <> Неопределено Тогда
ВызватьИсключение Задание.ИнформацияОбОшибке.ПодробноеОписаниеОшибки();
КонецЕсли;
юТест.ПроверитьРавенство(1, СчетчикВызовов, "Обработчик, подписанный до события, вызывается один раз");

КонецПроцедуры

ПодключитьСценарий(ТекущийСценарий().Источник, "ТестСобытий");
Loading