private string JsCodeForSetCookies(AbTestPersistentData test, int choice) { var cookieExpireDate = test.EndDate ?? DateTime.Today.AddYears(1); return($@" var options = {{}}; options.expires = new Date({cookieExpireDate.Year},{cookieExpireDate.Month - 1},{cookieExpireDate.Day},{cookieExpireDate.Hour},{cookieExpireDate.Minute}) options.path = '{Url.Action("InlineScript", "AbTest").ToLower()}'; cookies.set('{AbTestChoiceResolver.CookieNamePrefix + test.Id}', '{choice}', options); "); }
public AbTestInfo(AbTestPersistentData test, IEnumerable <AbTestContainerBasePersistentData> containers) { if (test != null && test.Percentage != null && containers != null && containers.Any()) { Enabled = test.Enabled; Id = test.Id; Title = test.Title; Comment = test.Comment; StartDate = test.StartDate; EndDate = test.EndDate; var sum = test.Percentage.Sum(); var vars = new List <AbTestVariantInfo>(); for (var i = 0; i < test.Percentage.Length; i++) { vars.Add(new AbTestVariantInfo(containers, i, Math.Round((100m * test.Percentage[i]) / sum, 2))); } Variants = vars; } }
/// <summary> /// Делаем выбор варианта для теста в рамках запроса. /// </summary> /// <param name="test">Тест</param> /// <returns>null - если тест отключен (никакой вариант не выбран), иначе номер варианта.</returns> public int?ResolveChoice(AbTestPersistentData test) { if (test == null) { throw new ArgumentNullException(nameof(test)); } var request = _httpContextAccessor.HttpContext.Request; //возможно выбор был уже сделан с рамках обработки этого запроса if (_currentChoices.ContainsKey(test.Id)) { return(_currentChoices[test.Id]); } //нужно понять включен ли на самом деле тест //он может быть включен\выключен в QP; еще у теста есть дата начала и окончания, они тоже влияют на его включенность var enabled = test.Enabled; if (enabled) { var now = DateTime.Now; enabled = (!test.StartDate.HasValue || test.StartDate.Value < now) && (!test.EndDate.HasValue || now < test.EndDate.Value); } //включенность может быть переопределена для текущего запроса (с помощью специальной force-куки) var forceCookie = request.Cookies[ForceCookieNamePrefix + test.Id]; if (forceCookie != null) { //в force-куки могут быть значения 0 или 1, другие игнорируем var force = ResolveChoiceFromString(forceCookie); if (force == 0 || force == 1) { enabled = force == 1; } } //если тест выключен - выбор по нему не делаем if (!enabled) { _currentChoices[test.Id] = null; return(null); } int?choice = null; //возможно выбор для AB теста передан в query-параметре (приоритетнее куки) string queryParamValue = request.Query[QueryParamPrefix + test.Id]; if (!String.IsNullOrWhiteSpace(queryParamValue)) { choice = ResolveChoiceFromString(queryParamValue); } //возможно выбор для AB теста передан в cookie if (!choice.HasValue) { var cookie = request.Cookies[CookieNamePrefix + test.Id]; if (cookie != null) { choice = ResolveChoiceFromString(cookie); } } //сделаем выбор на основе рандома if (!choice.HasValue) { var percentage = test.Percentage; if (percentage != null && percentage.Length > 1 && percentage.Sum() > 0) { int sum = percentage.Sum(); int random = new Random().Next(sum); for (int i = 0; i < percentage.Length; i++) { random -= percentage[i]; if (random < 0) { choice = i; break; } } } } //если выбор почему-то не был сделан, то делаем выбор по умолчанию if (!choice.HasValue) { //logger.Debug("AbTestChoiceResolver : getting default choice. testId = " + testId); choice = 0; } _currentChoices[test.Id] = choice; return(choice.Value); }
private string JsCodeForAbTestContext(AbTestPersistentData test, int?resolvedChoice) { return($@"window.abTestingContext['{AbTestChoiceResolver.CookieNamePrefix + test.Id}'] = {{ choice: {(resolvedChoice.HasValue ? resolvedChoice.Value.ToString() : "null")}, cids:[], targetedCids:[] }};"); }