import { StepBuilder } from "../../../src/steps/stepBuilder"; import BrandSafetyStep from "../../../src/steps/prebid/brandSafety.step"; import { FakeRequestBuilder } from "../fakeRequestBuilder"; import CategoryService from "../../../src/services/category.service"; import { CategoryRating, CategoryProviderType } from "../../../src/categories/categoryProvider"; import { reset, verify, mock, when, instance, objectContaining } from "ts-mockito"; import FeatureConfigFake from "../fake/FeatureConfigFake"; import { FeatureConfigService } from "../../../src/services/FeatureConfig.service"; import { expect } from "chai"; import { StepResult } from "../../../src/steps/stepResult"; import { FakeCampaign } from "../fake/Campaign"; import { MockCategoryValue } from "../../../src/categories/mockCategoryProvider"; import { CampaignModelFake } from "../fake/CampaignModelFake"; import { CampaignModel } from "../../../src/models/CampaignModel"; import { ChoiceRequest } from "../../../src/models/request.model"; const featureConfigService = FeatureConfigService.getInstance(); const mockedFeatureConf: FeatureConfigFake = new FeatureConfigFake(); const campaignModel: CampaignModel = new CampaignModelFake(); const innerBrandSafetyStep = new BrandSafetyStep(campaignModel, CategoryProviderType.DV, false); const brandSafetyStep = new StepBuilder(innerBrandSafetyStep).build(); let categoryService: CategoryService; describe("BrandSafetyStep", function () { before(async () => { categoryService = mock(CategoryService); innerBrandSafetyStep.categoryService = instance(categoryService); (innerBrandSafetyStep as any).featureConfigService = featureConfigService; featureConfigService.setFeatureConfig(mockedFeatureConf); }); after(async () => {}); beforeEach(async () => { mockedFeatureConf.clearParams(); reset(categoryService); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safe")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("unsafe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("unknown")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafeMedium")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe:unsafe:unsafe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafeLow")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe:safe:unsafe")); when( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safeWar")), CategoryProviderType.DV ) ).thenResolve(new MockCategoryValue("safe:safe:safe:80222009")); }); describe("Application are always safe on dv", function () { it("should flag this app bundle as safe", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withAppBundleOrDomain("http://www.ogury.com/unsafe") .withEnvironmentType("in-app") .withPrebid({ type: "brand-safety", provider: "dv" }) .withDeviceOS("android") .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe(stepRes, false, true, undefined, undefined, undefined); expect(request.campaigns[0].stepsPassedStatus["pass_brand_safety_dv"]).to.be.equal( "bypassed" ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag unknown appbundle as safe ", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withAppBundleOrDomain("http://www.ogury.com/unknown") .withEnvironmentType("in-app") .withPrebid({ type: "brand-safety", provider: "dv" }) .withDeviceOS("android") .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe(stepRes, false, true, undefined, undefined, undefined); expect(request.campaigns[0].stepsPassedStatus["pass_brand_safety_dv"]).to.be.equal( "bypassed" ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safe")), CategoryProviderType.DV ) ).never(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).never(); }); }); describe("Brand safety (WEB)", function () { it("should flag this domain as unsafe", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe( stepRes, true, false, CategoryRating.Unsafe, CategoryRating.Unsafe, CategoryRating.Unsafe ); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Unsafe); const excluded = request?.excluded || []; expect(excluded[0].stepsPassedStatus["pass_brand_safety_dv"]).to.be.equal("false"); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain as unsafe with multiple campaigns", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withEnvironmentType("web") .withCampaigns( new FakeCampaign("10001"), new FakeCampaign("10002"), new FakeCampaign("10003") ) .withCampaignPrebid("10002", { type: "brand-safety", provider: "ias" }) .withPrebid({ type: "brand-safety", provider: "dv" }) .withCampaignPrebid("10003", { type: "brand-safety", provider: "ias" }) .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe( stepRes, true, false, CategoryRating.Unsafe, CategoryRating.Unsafe, CategoryRating.Unsafe ); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Unsafe); const excluded = request?.excluded || []; expect(excluded[0].stepsPassedStatus["pass_brand_safety_dv"]).to.be.equal("false"); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain as unsafe with multiple campaigns on other provider", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withEnvironmentType("web") .withCampaigns( new FakeCampaign("10001"), new FakeCampaign("10002"), new FakeCampaign("10003") ) .withPrebid({ type: "brand-safety", provider: "ias" }) .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe(stepRes, true, true, undefined, undefined, undefined); expect(request.campaigns[0].stepsPassedStatus["pass_brand_safety_dv"]).to.be.equal( "bypassed" ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag this domain as unsafe with multiple campaigns on other provider and force cache", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.fill-cache.dv", "1"); const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withEnvironmentType("web") .withCampaigns( new FakeCampaign("10001"), new FakeCampaign("10002"), new FakeCampaign("10003") ) .withPrebid({ type: "brand-safety", provider: "ias" }) .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe(stepRes, true, true, undefined, undefined, undefined); expect(request.campaigns[0].stepsPassedStatus["pass_brand_safety_dv"]).to.be.equal( "bypassed" ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain as unsafe with multiple campaigns and various provider", async function () { const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafe") .withEnvironmentType("web") .withCampaigns( new FakeCampaign("10001"), new FakeCampaign("10002"), new FakeCampaign("10003") ) .withCampaignPrebid("10001", { type: "brand-safety", provider: "dv" }) .withCampaignPrebid("10002", { type: "brand-safety", provider: "ias" }) .withCampaignPrebid("10003", { type: "brand-safety", provider: "dv" }) .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafeWithoutCampaignLength( stepRes, true, false, CategoryRating.Unsafe, CategoryRating.Unsafe, CategoryRating.Unsafe ); stepRes.passedCampaigns.length.should.be.equal(1); stepRes.passedCampaigns[0].id.should.be.equal("10002"); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Unsafe); const excluded = request?.excluded || []; expect(excluded[0].stepsPassedStatus["pass_brand_safety_dv"]).to.be.equal("false"); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain as safe", async function () { const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safe") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Safe ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safe")), CategoryProviderType.DV ) ).once(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag this domain with war and no featureConfig as safe", async function () { mockedFeatureConf.removeParams(["ms-choices.brand-safety.custom-filtering.dv"]); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safeWar") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Safe ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safeWar")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain with war and feature config as unsafe", async function () { mockedFeatureConf.setParam( "ms-choices.brand-safety.custom-filtering.dv", "456,80222009,80099999" ); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safeWar") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, false, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Safe ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safeWar")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain with war and single feature config as unsafe", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.custom-filtering.dv", "80222009"); const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safeWar") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe( stepRes, true, false, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Safe ); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Unsafe); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safeWar")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain with war and bad feature config as safe", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.custom-filtering.dv", "456,80099999"); const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safeWar") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Safe ); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Safe); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safeWar")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain with war and empty feature config as safe", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.custom-filtering.dv", ""); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safeWar") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Safe ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safeWar")), CategoryProviderType.DV ) ).once(); }); it("should flag this domain without war and feature config as safe", async function () { mockedFeatureConf.setParam( "ms-choices.brand-safety.custom-filtering.dv", "456,80222009,80099999" ); const request = new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/safe") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build(); const stepRes = await brandSafetyStep.execute(request); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Safe ); checkPrebidResult(request, CategoryProviderType.DV, CategoryRating.Safe); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/safe")), CategoryProviderType.DV ) ).once(); }); it("should flag this unknown domain as unsafe", async function () { const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unknown") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, false, CategoryRating.Unknown, CategoryRating.Unknown, CategoryRating.Unknown ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).once(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); it("should flag this unknown domain as safe", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.allow-unknown.dv", "true"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unknown") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Unknown, CategoryRating.Unknown, CategoryRating.Unknown ); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unknown")), CategoryProviderType.DV ) ).once(); verify( categoryService.getPublisherCategoryValue( objectContaining(expectedRequest("http://www.ogury.com/unsafe")), CategoryProviderType.DV ) ).never(); }); describe("Brand safety check with different level with low unsafe", function () { it("should flag this domain as safe", async function () { mockedFeatureConf.removeParams(["ms-choices.brand-safety.severity.dv"]); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeLow") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Unsafe ); }); it("should flag this domain as safe with featureConfig High", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "high"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeLow") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Unsafe ); }); it("should flag this domain as safe with garbage featureConfig ", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "garbage"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeLow") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Unsafe ); }); it("should flag this domain as safe with featureConfig medium ", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "medium"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeLow") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Unsafe ); }); it("should flag this domain as unsafe with featureConfig low ", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "low"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeLow") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, false, CategoryRating.Safe, CategoryRating.Safe, CategoryRating.Unsafe ); }); }); describe("Brand safety check with different level with medium unsafe", function () { it("should flag this domain as safe", async function () { mockedFeatureConf.removeParams(["ms-choices.brand-safety.severity.dv"]); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Unsafe, CategoryRating.Unsafe ); }); it("should flag this domain as safe with featureConfig High", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "high"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Unsafe, CategoryRating.Unsafe ); }); it("should flag this domain as safe with garbage featureConfig ", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "garbage"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, true, CategoryRating.Safe, CategoryRating.Unsafe, CategoryRating.Unsafe ); }); it("should flag this domain as unsafe with featureConfig medium ", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "medium"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, false, CategoryRating.Safe, CategoryRating.Unsafe, CategoryRating.Unsafe ); }); it("should flag this domain as unsafe with featureConfig low ", async function () { mockedFeatureConf.setParam("ms-choices.brand-safety.severity.dv", "low"); const stepRes = await brandSafetyStep.execute( new FakeRequestBuilder() .withValidIpAndUserAgent() .withPage("http://www.ogury.com/unsafeMedium") .withPrebid({ type: "brand-safety", provider: "dv" }) .withEnvironmentType("web") .build() ); shouldBeSafe( stepRes, true, false, CategoryRating.Safe, CategoryRating.Unsafe, CategoryRating.Unsafe ); }); }); }); }); function shouldBeSafe( stepRes: StepResult, webmobile: boolean, passed: boolean, high: CategoryRating | undefined, medium: CategoryRating | undefined, low: CategoryRating | undefined ) { const passedCampaignLength = stepRes.passedCampaigns.length; if (passed) { passedCampaignLength.should.be.above(0); } else { passedCampaignLength.should.be.equal(0); } shouldBeSafeWithoutCampaignLength(stepRes, webmobile, passed, high, medium, low); } function shouldBeSafeWithoutCampaignLength( stepRes: StepResult, webmobile: boolean, passed: boolean, high: CategoryRating | undefined, medium: CategoryRating | undefined, low: CategoryRating | undefined ) { expect(stepRes.getMetricLabel("is_web_mobile")).to.be.equal(String(webmobile)); expect(stepRes.getMetricLabel("passed_brand_safety")).to.be.equal(String(passed)); expect(stepRes.getMetricLabel("brand_safety_high")).to.be.equal(high); expect(stepRes.getMetricLabel("brand_safety_medium")).to.be.equal(medium); expect(stepRes.getMetricLabel("brand_safety_low")).to.be.equal(low); } function expectedRequest(url: string): Object { return { site: { page: url, }, }; } function checkPrebidResult(request: ChoiceRequest, provider: CategoryProviderType, value: string) { expect(request.metadata.prebid_result).to.be.not.null; const result = request.metadata.prebid_result?.filter( (value) => value.step === "brand_safety" && value.provider === provider ); expect(result?.length).to.be.equal(1); expect(result![0].result).to.be.equal(value); }