Example #1
0
func (da *RedisDataAccess) DebitIfNotZero(accountKey string, amount int64, dailyBudget int64, dailyBudgetExpiration time.Time) (remainingDailyBudgetInMicroCents int64, err error) {
	client, err := da.pool.Get()

	if err != nil {
		panic(err)
	}

	defer da.pool.CarefullyPut(client, &err)
	accountKeyWithDomain := da.withDomain(accountKey)
	debitIfNotZeroSha := da.getDebitIfNotZeroSha()
	dailyBudgetSha := da.getDailyBudgetSha()

	client.Append("MULTI")
	client.Append("EVALSHA", dailyBudgetSha, 1, accountKeyWithDomain, dailyBudget, dailyBudgetExpiration.Unix())
	client.Append("EVALSHA", debitIfNotZeroSha, 1, accountKeyWithDomain, amount)
	client.Append("GET", accountKeyWithDomain)
	client.Append("EXEC")

	client.GetReply()
	client.GetReply()
	client.GetReply()
	client.GetReply()
	transaction := client.GetReply()
	if transaction.Err != nil {
		return 0, rtb.NewTransactionError(transaction.Err.Error(), false)
	}

	if err != nil {
		return 0, rtb.NewTransactionError(err.Error(), false)
	}

	amountValid := transaction.Elems[2].Type != redis.NilReply && transaction.Elems[2].Err == nil

	if amountValid {
		remainingDailyBudgetInMicroCents, _ = transaction.Elems[2].Int64()
	}
	if transaction.Elems[1].Type == redis.NilReply {
		return remainingDailyBudgetInMicroCents, rtb.NewTransactionError("Insufficient daily funds.", amountValid)
	} else {
		return remainingDailyBudgetInMicroCents, nil
	}
}
Example #2
0
// TestBiddingMatchedTarget tests that the bidder will bid on the first campaign returned by the bidder that has a remaining daily budget
// Expected result is a bid response that is populated by a single bid with a campaign ID matching the first campaigned returned by the provider
func TestBiddingFirstCampaignOutOfFunds(t *testing.T) {
	r := new(rtb.BidRequest)
	r.Imp = make([]rtb.Imp, 1)
	r.Imp[0] = rtb.Imp{}

	pacer := mocks.NewMockPacer(map[int64]bool{100: true, 101: true})

	campaign1 := mocks.NewMockCampaign(100, rtb.CpmToMicroCents(0.25), rtb.DollarsToMicroCents(1), nil)
	campaign2 := mocks.NewMockCampaign(101, rtb.CpmToMicroCents(0.25), rtb.DollarsToMicroCents(1), nil)

	campaignsReturnedByTargeting := []rtb.Campaign{campaign1, campaign2}

	cp := mocks.NewMockCampaignProvider(campaignsReturnedByTargeting, map[int64]int64{100: rtb.DollarsToMicroCents(1), 101: rtb.DollarsToMicroCents(1)}, map[int64]error{100: rtb.NewTransactionError("test", true), 101: nil}, nil)

	b := NewBidRequestBidder(r, cp, pacer, time.Now().UTC())

	response, _, err := b.Bid()

	if err != nil {
		t.Fail()
	}

	if response == nil {
		t.FailNow()
	}

	if response.Seatbid == nil {
		t.FailNow()
	}

	if len(response.Seatbid) != 1 {
		t.Fail()
	}

	if response.Seatbid[0].Bid == nil {
		t.FailNow()
	}

	if len(response.Seatbid[0].Bid) != 1 {
		t.FailNow()
	}

	if response.Seatbid[0].Bid[0].Cid != strconv.FormatInt(campaignsReturnedByTargeting[1].Id(), 10) {
		t.Fail()
	}
}
Example #3
0
// TestBiddingMatchedTarget tests that the bidder will not bid if a campaign is out of funds
// Expected result is nil
func TestBiddingMatchedTargetNoFundsAvailable(t *testing.T) {
	r := new(rtb.BidRequest)
	r.Imp = make([]rtb.Imp, 1)
	r.Imp[0] = rtb.Imp{}

	pacer := mocks.NewMockPacer(map[int64]bool{100: true})

	campaign := mocks.NewMockCampaign(100, rtb.CpmToMicroCents(0.25), rtb.DollarsToMicroCents(1), nil)

	campaignsReturnedByTargeting := []rtb.Campaign{campaign}

	cp := mocks.NewMockCampaignProvider(campaignsReturnedByTargeting, map[int64]int64{100: rtb.DollarsToMicroCents(1)}, map[int64]error{100: rtb.NewTransactionError("error", true)}, nil)

	b := NewBidRequestBidder(r, cp, pacer, time.Now().UTC())

	response, _, err := b.Bid()

	if err != nil {
		t.Fail()
	}

	if response != nil {
		t.FailNow()
	}
}