go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/server/quota/internal/luatest/testdata/account_test.lua (about) 1 -- Copyright 2022 The LUCI Authors 2 -- 3 -- Licensed under the Apache License, Version 2.0 (the "License"); 4 -- you may not use this file except in compliance with the License. 5 -- You may obtain a copy of the License at 6 -- 7 -- http://www.apache.org/licenses/LICENSE-2.0 8 -- 9 -- Unless required by applicable law or agreed to in writing, software 10 -- distributed under the License is distributed on an "AS IS" BASIS, 11 -- WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 -- See the License for the specific language governing permissions and 13 -- limitations under the License. 14 15 16 require 'test_fixtures' 17 18 Account = G.Account 19 Policy = G.Policy 20 Utils = G.Utils 21 22 local DO_NOT_CAP_PROPOSED = PB.E["go.chromium.org.luci.server.quota.quotapb.Op.Options"].DO_NOT_CAP_PROPOSED 23 local IGNORE_POLICY_BOUNDS = PB.E["go.chromium.org.luci.server.quota.quotapb.Op.Options"].IGNORE_POLICY_BOUNDS 24 local WITH_POLICY_LIMIT_DELTA = PB.E["go.chromium.org.luci.server.quota.quotapb.Op.Options"].WITH_POLICY_LIMIT_DELTA 25 26 function enumMap(e) 27 local ret = {} 28 for k, v in pairs(PB.E[e]) do 29 if type(k) == "string" then 30 ret[k] = k 31 end 32 end 33 return ret 34 end 35 36 local AccountStatus = enumMap("go.chromium.org.luci.server.quota.quotapb.OpResult.AccountStatus") 37 local OpStatus = enumMap("go.chromium.org.luci.server.quota.quotapb.OpResult.OpStatus") 38 39 function mkOp(fields) 40 return PB.new("go.chromium.org.luci.server.quota.quotapb.RawOp", fields) 41 end 42 43 function setPolicy(policy_config, policy_key, policy_params) 44 local ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 45 config = policy_config, 46 key = policy_key, 47 }) 48 local policy = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", policy_params) 49 50 redis.call("HSET", ref.config, ref.key, PB.marshal(policy)) 51 52 return ref 53 end 54 55 function testAccountGetEmpty() 56 local account = Account:get(KEYS[1]) 57 lu.assertEquals(account.account_status, AccountStatus.CREATED) 58 lu.assertEquals(account.key, KEYS[1], "account key is saved") 59 end 60 61 function testSaveEmptyAccount() 62 local account = Account:get(KEYS[1]) 63 account:write() 64 lu.assertEquals(#redis.DATA, 0, "save is a NOOP until we set a value.") 65 end 66 67 -- Use `./datatool -type Account -out msgpackpb+lua` 68 -- 69 -- { 70 -- "balance": 100, 71 -- "updated_ts": "2022-12-12T08:41:26+00:00" 72 -- } 73 -- 74 -- The msgpackpb+pretty of this is: 75 -- [ 76 -- 8i100, 77 -- [ 78 -- 32u1670834486, 79 -- ], 80 -- ] 81 local packedAccount = "\146d\145\206c\150\2336" 82 83 function testAccountSetValue() 84 local account = Account:get(KEYS[1]) 85 account.pb.balance = 100 86 87 account:write() 88 lu.assertEquals(redis.DATA[KEYS[1]], packedAccount, "data is saved in packed form") 89 end 90 91 function testAccountLoad() 92 redis.call("SET", KEYS[1], packedAccount) 93 local account = Account:get(KEYS[1]) 94 95 lu.assertEquals(account.pb.balance, 100) 96 lu.assertEquals(account.pb.updated_ts.seconds, 1670834486) 97 end 98 99 function testNilAccountSetPolicy() 100 local account = Account:get(KEYS[1]) 101 local policy = { 102 policy_ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 103 config = "policy_key", 104 key = "policy_name", 105 }), 106 pb = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", { 107 default = 100, 108 limit = 1000, 109 refill = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy.Refill", { 110 units = 1, 111 interval = 1, 112 }), 113 lifetime = PB.new("google.protobuf.Duration", { 114 seconds = 123, 115 }) 116 }), 117 } 118 119 account:setPolicy(policy) 120 121 lu.assertEquals(account.pb.balance, policy.pb.default) 122 123 account:write() 124 125 lu.assertEquals(account.pb.updated_ts, Utils.NOW) 126 127 lu.assertEquals(redis.DATA[KEYS[1]], "\149d\145\206c\150\2336\145\206c\150\2336\146\170policy_key\171policy_name\132\001d\002\205\003\232\003\146\001\001\005\145{") 128 lu.assertEquals(redis.TTL[KEYS[1]], 123000) 129 end 130 131 function testNilAccountSetPolicyNoRefill() 132 local account = Account:get(KEYS[1]) 133 local policy = { 134 policy_ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 135 config = "policy_key", 136 key = "policy_name", 137 }), 138 pb = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", { 139 default = 100, 140 limit = 1000, 141 lifetime = PB.new("google.protobuf.Duration", { 142 seconds = 123, 143 }) 144 }), 145 } 146 147 account:setPolicy(policy) 148 149 lu.assertEquals(account.pb.balance, policy.pb.default) 150 lu.assertEquals(account.pb.updated_ts, Utils.NOW) 151 152 account:write() 153 154 lu.assertEquals(redis.DATA[KEYS[1]], "\149d\145\206c\150\2336\145\206c\150\2336\146\170policy_key\171policy_name\131\001d\002\205\003\232\005\145{") 155 lu.assertEquals(redis.TTL[KEYS[1]], 123000) 156 end 157 158 function testNilAccountSetPolicyInfinite() 159 local account = Account:get(KEYS[1]) 160 local policy = { 161 policy_ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 162 config = "policy_key", 163 key = "policy_name", 164 }), 165 pb = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", { 166 default = 100, 167 limit = 1000, 168 refill = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy.Refill", { 169 units = 1, 170 interval = 0, -- infinity 171 }), 172 lifetime = PB.new("google.protobuf.Duration", { 173 seconds = 123, 174 }) 175 }), 176 } 177 178 account:setPolicy(policy) 179 lu.assertEquals(account.pb.balance, policy.pb.limit) 180 181 -- note; this is not quite real, ApplyOps would be the only way to do this, 182 -- and it will explicitly avoid decreasing the balance. However applyRefill 183 -- on get should restore this. 184 account.pb.balance = 2 185 lu.assertEquals(account.pb.balance, 2) 186 187 account:write() 188 Account.CACHE = {} 189 account = Account:get(KEYS[1]) 190 lu.assertEquals(account.pb.balance, policy.pb.limit) 191 192 lu.assertEquals(redis.DATA[KEYS[1]], "\149\002\145\206c\150\2336\145\206c\150\2336\146\170policy_key\171policy_name\132\001d\002\205\003\232\003\145\001\005\145{") 193 lu.assertEquals(redis.TTL[KEYS[1]], 123000) 194 end 195 196 function testAccountSetPolicyRefill() 197 local account = Account:get(KEYS[1]) 198 account.pb.balance = 100 199 account:write() 200 201 lu.assertEquals(account.pb.balance, 100) 202 lu.assertEquals(account.pb.updated_ts, Utils.NOW) 203 204 Utils.NOW.seconds = Utils.NOW.seconds + 3 205 206 local policy = { 207 policy_ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 208 config = "policy_key", 209 key = "policy_name", 210 }), 211 pb = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", { 212 default = 100, 213 limit = 1000, 214 refill = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy.Refill", { 215 units = 1, 216 interval = 2, 217 }), 218 lifetime = PB.new("google.protobuf.Duration", { 219 seconds = 123, 220 }) 221 }), 222 } 223 224 account:setPolicy(policy) 225 226 lu.assertEquals(account.pb.balance, 100) 227 lu.assertEquals(account.pb.policy_ref.config, "policy_key") 228 lu.assertEquals(account.pb.policy_ref.key, "policy_name") 229 lu.assertEquals(account.pb.policy.limit, 1000) 230 lu.assertEquals(account.pb.policy.refill.interval, 2) 231 lu.assertEquals(account.pb.policy_change_ts, Utils.NOW) 232 233 account:write() 234 235 Utils.NOW.seconds = Utils.NOW.seconds + 3 236 Account.CACHE = {} 237 account = Account:get(KEYS[1]) 238 lu.assertEquals(account.pb.balance, 102) 239 240 Utils.NOW.seconds = Utils.NOW.seconds + 1 241 Account.CACHE = {} 242 account = Account:get(KEYS[1]) 243 lu.assertEquals(account.pb.balance, 102) 244 245 Utils.NOW.seconds = Utils.NOW.seconds + 1 246 Account.CACHE = {} 247 account = Account:get(KEYS[1]) 248 lu.assertEquals(account.pb.balance, 103) 249 250 account:write() 251 lu.assertEquals(redis.DATA[KEYS[1]], "\149g\145\206c\150\233>\145\206c\150\2339\146\170policy_key\171policy_name\132\001d\002\205\003\232\003\146\001\002\005\145{") 252 lu.assertEquals(redis.TTL[KEYS[1]], 123000) 253 end 254 255 function testAccountBalanceExtreme() 256 local account = Account:get(KEYS[1]) 257 account.pb.balance = 9007199254740991 258 account:write() -- ok 259 260 account.pb.balance = 9007199254740991 + 1 261 lu.assertErrorMsgContains("overflow", account.write, account) 262 263 account.pb.balance = -9007199254740991 264 account:write() -- ok 265 266 account.pb.balance = -9007199254740991 - 1 267 lu.assertErrorMsgContains("underflows", account.write, account) 268 end 269 270 function testAccountApplyOpFinitePolicy() 271 local account = Account:get(KEYS[1]) 272 273 local updateAccountPolicy = function(config, key, limit) 274 local p = { 275 pb = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", { 276 limit = limit, 277 }), 278 policy_ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 279 config = config, 280 key = key, 281 }), 282 } 283 account:setPolicy(p) 284 end 285 286 local setOp = function(cur, amt, options, relative_to, ref) 287 account.pb.balance = cur 288 return mkOp({ 289 delta = amt, 290 relative_to = relative_to or "ZERO", 291 options = options or 0, 292 policy_ref = ref, 293 }) 294 end 295 296 updateAccountPolicy("policy_key", "policy_name", 1000) 297 298 lu.assertEquals(account:applyOp(setOp(20, 300)), nil) -- increase < limit 299 lu.assertEquals(account.pb.balance, 300) 300 lu.assertEquals(account:applyOp(setOp(20, 5)), nil) -- decrease > 0 301 lu.assertEquals(account.pb.balance, 5) 302 lu.assertEquals(account:applyOp(setOp(20, 1000)), nil) -- increase == limit 303 lu.assertEquals(account.pb.balance, 1000) 304 lu.assertEquals(account:applyOp(setOp(20, 0)), nil) -- decrease == 0 305 lu.assertEquals(account.pb.balance, 0) 306 307 lu.assertEquals(account:applyOp(setOp(-100, 300)), nil) -- increase < limit 308 lu.assertEquals(account.pb.balance, 300) 309 lu.assertEquals(account:applyOp(setOp(-100, -50)), nil) -- increase < limit 310 lu.assertEquals(account.pb.balance, -50) 311 lu.assertEquals(account:applyOp(setOp(-100, 0)), nil) -- increase == 0 312 lu.assertEquals(account.pb.balance, 0) 313 lu.assertEquals(account:applyOp(setOp(-100, 1000)), nil) -- increase == limit 314 lu.assertEquals(account.pb.balance, 1000) 315 316 lu.assertEquals(account:applyOp(setOp(2000, 300)), nil) -- decrease < limit 317 lu.assertEquals(account.pb.balance, 300) 318 lu.assertEquals(account:applyOp(setOp(2000, 1000)), nil) -- decrease == limit 319 lu.assertEquals(account.pb.balance, 1000) 320 lu.assertEquals(account:applyOp(setOp(2000, 0)), nil) -- decrease == 0 321 lu.assertEquals(account.pb.balance, 0) 322 323 -- soft cap 324 lu.assertEquals(account:applyOp(setOp(2000, 1500)), nil) -- decrease < limit 325 lu.assertEquals(account.pb.balance, 1000) 326 -- hard cap 327 lu.assertEquals(account:applyOp(setOp(2000, 1500, DO_NOT_CAP_PROPOSED)), nil) -- decrease < limit 328 lu.assertEquals(account.pb.balance, 1500) 329 330 local rslt = {} 331 Account.applyOp(account, setOp(20, -1), rslt) 332 lu.assertEquals(rslt.status, "ERR_UNDERFLOW") 333 lu.assertEquals(account.pb.balance, 20) 334 335 local rslt = {} 336 Account.applyOp(account, setOp(-100, -200), rslt) 337 lu.assertEquals(rslt.status, "ERR_UNDERFLOW") 338 lu.assertEquals(account.pb.balance, -100) 339 340 local rslt = {} 341 Account.applyOp(account, setOp(20, 1001, DO_NOT_CAP_PROPOSED), rslt) 342 lu.assertEquals(rslt.status, "ERR_OVERFLOW") 343 lu.assertEquals(account.pb.balance, 20) 344 345 local rslt = {} 346 Account.applyOp(account, setOp(1500, 2000, DO_NOT_CAP_PROPOSED), rslt) 347 lu.assertEquals(rslt.status, "ERR_OVERFLOW") 348 lu.assertEquals(account.pb.balance, 1500) 349 350 -- WITH_POLICY_LIMIT_DELTA test cases 351 local rslt = {} 352 updateAccountPolicy("config1", "key1", 5) 353 local ref = setPolicy("config2", "key2", {limit = 10}) 354 Account.applyOp(account, setOp(3, -2, WITH_POLICY_LIMIT_DELTA, "CURRENT_BALANCE", ref), rslt) -- policy limit increase 5 < 10 355 lu.assertEquals(rslt.previous_balance_adjusted, 8) 356 lu.assertEquals(account.pb.balance, 6) 357 358 local rslt = {} 359 local ref = setPolicy("config3", "key3", {limit = 5}) 360 Account.applyOp(account, setOp(3, 1, WITH_POLICY_LIMIT_DELTA, "CURRENT_BALANCE", ref), rslt) -- policy limit decrease 10 > 5 361 lu.assertEquals(rslt.previous_balance_adjusted, -2) 362 lu.assertEquals(account.pb.balance, -1) 363 364 local rslt = {} 365 local ref = setPolicy("config4", "key4", {limit = 5}) 366 Account.applyOp(account, setOp(3, 1, WITH_POLICY_LIMIT_DELTA, "CURRENT_BALANCE", ref), rslt) -- old limit == new limit 367 lu.assertEquals(rslt.previous_balance_adjusted, 3) 368 lu.assertEquals(account.pb.balance, 4) 369 370 account:setPolicy(nil) -- unset policy 371 local rslt = {} 372 local ref = setPolicy("config5", "key5", {limit = 5}) 373 Account.applyOp(account, setOp(3, 1, WITH_POLICY_LIMIT_DELTA, "CURRENT_BALANCE", ref), rslt) -- no-op since old policy_Ref == nil 374 lu.assertEquals(rslt.previous_balance_adjusted, nil) 375 lu.assertEquals(account.pb.balance, 4) 376 end 377 378 function testAccountApplyOpInfinitePolicy() 379 local account = Account:get(KEYS[1]) 380 381 local p = { 382 pb = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", { 383 limit = 1000, 384 refill = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy.Refill", { 385 units = 1, 386 }) 387 }), 388 policy_ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 389 config = "policy_key", 390 key = "policy_name", 391 }), 392 } 393 account:setPolicy(p) 394 395 -- note: we do not need to test cases where the current balance is something 396 -- other than `pb.policy.limit`. We rely on Account construction and setPolicy 397 -- to call applyRefill(), and for applyOp to always leave balance >= limit. 398 local setOp = function(amt, options) 399 account.pb.balance = p.pb.limit 400 return mkOp({ 401 delta = amt, 402 relative_to = "ZERO", 403 options = options or 0, 404 }) 405 end 406 407 lu.assertEquals(account:applyOp(setOp(0)), nil) 408 lu.assertEquals(account.pb.balance, 1000) 409 lu.assertEquals(account:applyOp(setOp(1000)), nil) 410 lu.assertEquals(account.pb.balance, 1000) 411 lu.assertEquals(account:applyOp(setOp(500)), nil) 412 lu.assertEquals(account.pb.balance, 1000) 413 lu.assertEquals(account:applyOp(setOp(1234)), nil) 414 lu.assertEquals(account.pb.balance, 1000) 415 416 -- we can, however, start with a higher than limit balance. 417 local op = setOp(1234, DO_NOT_CAP_PROPOSED) 418 account.pb.balance = 2000 419 lu.assertEquals(account:applyOp(op), nil) 420 lu.assertEquals(account.pb.balance, 1234) 421 422 local rslt = {} 423 Account.applyOp(account, setOp(-1000), rslt) 424 lu.assertEquals(rslt.status, "ERR_UNDERFLOW") 425 lu.assertEquals(account.pb.balance, 1000) 426 427 local rslt = {} 428 Account.applyOp(account, setOp(1001, DO_NOT_CAP_PROPOSED), rslt) 429 lu.assertEquals(rslt.status, "ERR_OVERFLOW") 430 lu.assertEquals(account.pb.balance, 1000) 431 432 local rslt = {} 433 Account.applyOp(account, setOp(-1), rslt) 434 lu.assertEquals(rslt.status, "ERR_UNDERFLOW") 435 lu.assertEquals(account.pb.balance, 1000) 436 end 437 438 function testAccountApplyOpZeroPolicy() 439 local account = Account:get(KEYS[1]) 440 441 local p = { 442 pb = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy", { 443 limit = 0, 444 }), 445 policy_ref = PB.new("go.chromium.org.luci.server.quota.quotapb.PolicyRef", { 446 config = "policy_key", 447 key = "policy_name", 448 }), 449 } 450 account:setPolicy(p) 451 452 local setOp = function(cur, amt, options) 453 account.pb.balance = cur 454 return mkOp({ 455 delta = amt, 456 relative_to = "ZERO", 457 options = options, 458 }) 459 end 460 461 lu.assertEquals(account:applyOp(setOp(0, 0)), nil) 462 lu.assertEquals(account.pb.balance, 0) 463 lu.assertEquals(account:applyOp(setOp(100, 1)), nil) 464 lu.assertEquals(account.pb.balance, 0) 465 lu.assertEquals(account:applyOp(setOp(100, 1, DO_NOT_CAP_PROPOSED)), nil) 466 lu.assertEquals(account.pb.balance, 1) 467 lu.assertEquals(account:applyOp(setOp(2000, 1000)), nil) 468 lu.assertEquals(account.pb.balance, 0) 469 lu.assertEquals(account:applyOp(setOp(2000, 1000, DO_NOT_CAP_PROPOSED)), nil) 470 lu.assertEquals(account.pb.balance, 1000) 471 lu.assertEquals(account:applyOp(setOp(-2000, -1000)), nil) 472 lu.assertEquals(account.pb.balance, -1000) 473 474 local rslt = {} 475 Account.applyOp(account, setOp(0, 1000, DO_NOT_CAP_PROPOSED), rslt) 476 lu.assertEquals(rslt.status, "ERR_OVERFLOW") 477 lu.assertEquals(account.pb.balance, 0) 478 479 local rslt = {} 480 Account.applyOp(account, setOp(-100, 1, DO_NOT_CAP_PROPOSED), rslt) 481 lu.assertEquals(rslt.status, "ERR_OVERFLOW") 482 lu.assertEquals(account.pb.balance, -100) 483 484 local rslt = {} 485 Account.applyOp(account, setOp(0, 1, DO_NOT_CAP_PROPOSED), rslt) 486 lu.assertEquals(rslt.status, "ERR_OVERFLOW") 487 lu.assertEquals(account.pb.balance, 0) 488 489 local rslt = {} 490 Account.applyOp(account, setOp(0, -1), rslt) 491 lu.assertEquals(rslt.status, "ERR_UNDERFLOW") 492 lu.assertEquals(account.pb.balance, 0) 493 end 494 495 function testAccountApplyOpAddPolicy() 496 local ref = setPolicy("policy_config", "policy_name", { 497 default = 20, 498 limit = 100, 499 refill = PB.new("go.chromium.org.luci.server.quota.quotapb.Policy.Refill", { 500 units = 1, 501 interval = 100, 502 }), 503 lifetime = PB.new("google.protobuf.Duration", { 504 seconds = 3600, 505 }), 506 }) 507 508 local account = Account:get(KEYS[1]) 509 510 account:applyOp(mkOp({ 511 policy_ref = ref, 512 relative_to = "CURRENT_BALANCE", 513 delta = 13, 514 })) 515 516 lu.assertEquals(account.pb.balance, 33) 517 end 518 519 function testApplyOpsOK() 520 local pol_one = setPolicy("policy_config", "one", { 521 default = 10, 522 limit = 100, 523 }) 524 local pol_two = setPolicy("policy_config", "two", { 525 default = 20, 526 limit = 200, 527 }) 528 529 local rsp, allOK = Account.ApplyOps({ 530 mkOp({ 531 account_ref = "acct1", 532 policy_ref = pol_one, 533 relative_to = "CURRENT_BALANCE", 534 delta = 100, -- should hit limit, stop at 100. 535 }), 536 mkOp({ 537 account_ref = "acct2", 538 policy_ref = pol_two, 539 relative_to = "CURRENT_BALANCE", 540 delta = 100, -- stop at 120 under limit. 541 }), 542 }) 543 544 lu.assertTrue(allOK) 545 lu.assertEquals(#rsp.results, 2) 546 lu.assertEquals(rsp.results[1].account_status, AccountStatus.CREATED) 547 lu.assertEquals(rsp.results[1].status_msg, "") 548 lu.assertEquals(rsp.results[1].status, OpStatus.SUCCESS) 549 lu.assertEquals(rsp.results[1].previous_balance, 0) 550 lu.assertEquals(rsp.results[1].new_balance, 100) 551 552 lu.assertEquals(rsp.results[2].account_status, AccountStatus.CREATED) 553 lu.assertEquals(rsp.results[2].status_msg, "") 554 lu.assertEquals(rsp.results[2].status, OpStatus.SUCCESS) 555 lu.assertEquals(rsp.results[2].previous_balance, 0) 556 lu.assertEquals(rsp.results[2].new_balance, 120) 557 end 558 559 function testApplyOpsFail() 560 local pol_one = setPolicy("policy_config", "one", { 561 default = 10, 562 limit = 100, 563 }) 564 565 local rsp, allOK = Account.ApplyOps({ 566 mkOp({ 567 account_ref = "acct1", 568 relative_to = "CURRENT_BALANCE", 569 options = DO_NOT_CAP_PROPOSED + IGNORE_POLICY_BOUNDS, 570 delta = 1000, 571 }), 572 573 mkOp({ 574 account_ref = "acct2", 575 policy_ref = pol_one, 576 relative_to = "CURRENT_BALANCE", 577 options = DO_NOT_CAP_PROPOSED, 578 delta = 1000, 579 }), 580 581 mkOp({ 582 account_ref = "acct3", 583 policy_ref = pol_one, 584 relative_to = "CURRENT_BALANCE", 585 delta = -1000, 586 }), 587 588 mkOp({ 589 account_ref = "acct4", 590 policy_ref = {config = "nope", key = "missing"}, 591 relative_to = "CURRENT_BALANCE", 592 delta = 100, 593 }), 594 595 mkOp({ 596 account_ref = "acct5", 597 relative_to = "CURRENT_BALANCE", 598 delta = 100, 599 }), 600 601 mkOp({ 602 account_ref = "acct6", 603 relative_to = "ZERO", 604 delta = 100, 605 }), 606 }) 607 608 lu.assertFalse(allOK) 609 lu.assertEquals(#rsp.results, 6) 610 lu.assertEquals(rsp.results[1].account_status, AccountStatus.CREATED) 611 lu.assertStrContains(rsp.results[1].status_msg, "IGNORE_POLICY_BOUNDS and DO_NOT_CAP_PROPOSED both set") 612 lu.assertEquals(rsp.results[1].status, OpStatus.ERR_UNKNOWN) 613 614 lu.assertEquals(rsp.results[2].account_status, AccountStatus.CREATED) 615 lu.assertEquals(rsp.results[2].status_msg, "") 616 lu.assertEquals(rsp.results[2].status, OpStatus.ERR_OVERFLOW) 617 618 lu.assertEquals(rsp.results[3].account_status, AccountStatus.CREATED) 619 lu.assertEquals(rsp.results[3].status, OpStatus.ERR_UNDERFLOW) 620 lu.assertEquals(rsp.results[3].status_msg, "") 621 622 lu.assertEquals(rsp.results[4].account_status, AccountStatus.CREATED) 623 lu.assertEquals(rsp.results[4].status, OpStatus.ERR_UNKNOWN_POLICY) 624 lu.assertEquals(rsp.results[4].status_msg, "") 625 626 lu.assertEquals(rsp.results[5].account_status, AccountStatus.CREATED) 627 lu.assertEquals(rsp.results[5].status_msg, "") 628 lu.assertEquals(rsp.results[5].status, OpStatus.ERR_POLICY_REQUIRED) 629 end 630 631 function testApplyOpsMultiSameAccount() 632 local req = PB.new("go.chromium.org.luci.server.quota.quotapb.ApplyOpsRequest", { 633 634 }) 635 end 636 637 return lu.LuaUnit.run("-v")