|
6 | 6 | from six.moves import cStringIO as StringIO
|
7 | 7 |
|
8 | 8 | from simple_history import models as sh_models
|
9 |
| -from simple_history.management.commands import populate_history, clean_duplicate_history |
| 9 | +from simple_history.management.commands import ( |
| 10 | + populate_history, |
| 11 | + clean_duplicate_history, |
| 12 | + clean_old_history, |
| 13 | +) |
10 | 14 | from ..models import (
|
11 | 15 | Book,
|
12 | 16 | CustomManagerNameModel,
|
@@ -381,3 +385,196 @@ def test_auto_cleanup_custom_history_field(self):
|
381 | 385 | "<class 'simple_history.tests.models.CustomManagerNameModel'>\n",
|
382 | 386 | )
|
383 | 387 | self.assertEqual(CustomManagerNameModel.log.all().count(), 2)
|
| 388 | + |
| 389 | + |
| 390 | +class TestCleanOldHistory(TestCase): |
| 391 | + command_name = "clean_old_history" |
| 392 | + command_error = (management.CommandError, SystemExit) |
| 393 | + |
| 394 | + def test_no_args(self): |
| 395 | + out = StringIO() |
| 396 | + management.call_command(self.command_name, stdout=out, stderr=StringIO()) |
| 397 | + self.assertIn(clean_old_history.Command.COMMAND_HINT, out.getvalue()) |
| 398 | + |
| 399 | + def test_bad_args(self): |
| 400 | + test_data = ( |
| 401 | + (clean_old_history.Command.MODEL_NOT_HISTORICAL, ("tests.place",)), |
| 402 | + (clean_old_history.Command.MODEL_NOT_FOUND, ("invalid.model",)), |
| 403 | + (clean_old_history.Command.MODEL_NOT_FOUND, ("bad_key",)), |
| 404 | + ) |
| 405 | + for msg, args in test_data: |
| 406 | + out = StringIO() |
| 407 | + self.assertRaises( |
| 408 | + self.command_error, |
| 409 | + management.call_command, |
| 410 | + self.command_name, |
| 411 | + *args, |
| 412 | + stdout=StringIO(), |
| 413 | + stderr=out |
| 414 | + ) |
| 415 | + self.assertIn(msg, out.getvalue()) |
| 416 | + |
| 417 | + def test_no_historical(self): |
| 418 | + out = StringIO() |
| 419 | + with replace_registry({"test_place": Place}): |
| 420 | + management.call_command(self.command_name, auto=True, stdout=out) |
| 421 | + self.assertIn(clean_old_history.Command.NO_REGISTERED_MODELS, out.getvalue()) |
| 422 | + |
| 423 | + def test_auto_dry_run(self): |
| 424 | + p = Poll.objects.create( |
| 425 | + question="Will this be deleted?", pub_date=datetime.now() |
| 426 | + ) |
| 427 | + p.save() |
| 428 | + |
| 429 | + # not related to dry_run test, just for increasing coverage :) |
| 430 | + # create instance with single-entry history older than "minutes" |
| 431 | + # so it is skipped |
| 432 | + p = Poll.objects.create( |
| 433 | + question="Will this be deleted?", pub_date=datetime.now() |
| 434 | + ) |
| 435 | + h = p.history.first() |
| 436 | + h.history_date -= timedelta(days=31) |
| 437 | + h.save() |
| 438 | + |
| 439 | + self.assertEqual(Poll.history.all().count(), 3) |
| 440 | + out = StringIO() |
| 441 | + management.call_command( |
| 442 | + self.command_name, |
| 443 | + auto=True, |
| 444 | + days=20, |
| 445 | + dry=True, |
| 446 | + stdout=out, |
| 447 | + stderr=StringIO(), |
| 448 | + ) |
| 449 | + self.assertEqual( |
| 450 | + out.getvalue(), |
| 451 | + "Removed 1 historical records for " |
| 452 | + "<class 'simple_history.tests.models.Poll'>\n", |
| 453 | + ) |
| 454 | + self.assertEqual(Poll.history.all().count(), 3) |
| 455 | + |
| 456 | + def test_auto_cleanup(self): |
| 457 | + p = Poll.objects.create( |
| 458 | + question="Will this be deleted?", pub_date=datetime.now() |
| 459 | + ) |
| 460 | + self.assertEqual(Poll.history.all().count(), 1) |
| 461 | + p.save() |
| 462 | + self.assertEqual(Poll.history.all().count(), 2) |
| 463 | + p.question = "Maybe this one won't...?" |
| 464 | + p.save() |
| 465 | + self.assertEqual(Poll.history.all().count(), 3) |
| 466 | + out = StringIO() |
| 467 | + h = p.history.first() |
| 468 | + h.history_date -= timedelta(days=40) |
| 469 | + h.save() |
| 470 | + management.call_command( |
| 471 | + self.command_name, auto=True, stdout=out, stderr=StringIO() |
| 472 | + ) |
| 473 | + self.assertEqual( |
| 474 | + out.getvalue(), |
| 475 | + "Removed 1 historical records for " |
| 476 | + "<class 'simple_history.tests.models.Poll'>\n", |
| 477 | + ) |
| 478 | + self.assertEqual(Poll.history.all().count(), 2) |
| 479 | + |
| 480 | + def test_auto_cleanup_verbose(self): |
| 481 | + p = Poll.objects.create( |
| 482 | + question="Will this be deleted?", pub_date=datetime.now() |
| 483 | + ) |
| 484 | + self.assertEqual(Poll.history.all().count(), 1) |
| 485 | + p.save() |
| 486 | + p.question = "Maybe this one won't...?" |
| 487 | + p.save() |
| 488 | + h = p.history.first() |
| 489 | + h.history_date -= timedelta(days=40) |
| 490 | + h.save() |
| 491 | + self.assertEqual(Poll.history.all().count(), 3) |
| 492 | + out = StringIO() |
| 493 | + management.call_command( |
| 494 | + self.command_name, |
| 495 | + "tests.poll", |
| 496 | + auto=True, |
| 497 | + verbosity=2, |
| 498 | + stdout=out, |
| 499 | + stderr=StringIO(), |
| 500 | + ) |
| 501 | + |
| 502 | + self.assertEqual( |
| 503 | + out.getvalue(), |
| 504 | + "<class 'simple_history.tests.models.Poll'> has 1 old historical entries\n" |
| 505 | + "Removed 1 historical records for " |
| 506 | + "<class 'simple_history.tests.models.Poll'>\n", |
| 507 | + ) |
| 508 | + self.assertEqual(Poll.history.all().count(), 2) |
| 509 | + |
| 510 | + def test_auto_cleanup_dated(self): |
| 511 | + the_time_is_now = datetime.now() |
| 512 | + p = Poll.objects.create( |
| 513 | + question="Will this be deleted?", pub_date=the_time_is_now |
| 514 | + ) |
| 515 | + self.assertEqual(Poll.history.all().count(), 1) |
| 516 | + p.save() |
| 517 | + p.save() |
| 518 | + self.assertEqual(Poll.history.all().count(), 3) |
| 519 | + p.question = "Or this one...?" |
| 520 | + p.save() |
| 521 | + p.save() |
| 522 | + self.assertEqual(Poll.history.all().count(), 5) |
| 523 | + |
| 524 | + for h in Poll.history.all()[2:]: |
| 525 | + h.history_date -= timedelta(days=30) |
| 526 | + h.save() |
| 527 | + |
| 528 | + management.call_command( |
| 529 | + self.command_name, auto=True, days=20, stdout=StringIO(), stderr=StringIO(), |
| 530 | + ) |
| 531 | + self.assertEqual(Poll.history.all().count(), 2) |
| 532 | + |
| 533 | + def test_auto_cleanup_dated_extra_one(self): |
| 534 | + the_time_is_now = datetime.now() |
| 535 | + p = Poll.objects.create( |
| 536 | + question="Will this be deleted?", pub_date=the_time_is_now |
| 537 | + ) |
| 538 | + self.assertEqual(Poll.history.all().count(), 1) |
| 539 | + p.save() |
| 540 | + p.save() |
| 541 | + self.assertEqual(Poll.history.all().count(), 3) |
| 542 | + p.question = "Or this one...?" |
| 543 | + p.save() |
| 544 | + p.save() |
| 545 | + p.save() |
| 546 | + p.save() |
| 547 | + self.assertEqual(Poll.history.all().count(), 7) |
| 548 | + |
| 549 | + for h in Poll.history.all()[2:]: |
| 550 | + h.history_date -= timedelta(days=30) |
| 551 | + h.save() |
| 552 | + |
| 553 | + management.call_command( |
| 554 | + self.command_name, auto=True, days=20, stdout=StringIO(), stderr=StringIO(), |
| 555 | + ) |
| 556 | + # We will remove the 3 ones that we are marking as old |
| 557 | + self.assertEqual(Poll.history.all().count(), 2) |
| 558 | + |
| 559 | + def test_auto_cleanup_custom_history_field(self): |
| 560 | + m = CustomManagerNameModel.objects.create(name="John") |
| 561 | + self.assertEqual(CustomManagerNameModel.log.all().count(), 1) |
| 562 | + m.save() |
| 563 | + self.assertEqual(CustomManagerNameModel.log.all().count(), 2) |
| 564 | + m.name = "Ivan" |
| 565 | + m.save() |
| 566 | + h = m.log.first() |
| 567 | + h.history_date -= timedelta(days=40) |
| 568 | + h.save() |
| 569 | + self.assertEqual(CustomManagerNameModel.log.all().count(), 3) |
| 570 | + out = StringIO() |
| 571 | + management.call_command( |
| 572 | + self.command_name, auto=True, stdout=out, stderr=StringIO() |
| 573 | + ) |
| 574 | + |
| 575 | + self.assertEqual( |
| 576 | + out.getvalue(), |
| 577 | + "Removed 1 historical records for " |
| 578 | + "<class 'simple_history.tests.models.CustomManagerNameModel'>\n", |
| 579 | + ) |
| 580 | + self.assertEqual(CustomManagerNameModel.log.all().count(), 2) |
0 commit comments