Skip to content

Increase test coverage of storage tests for single worker cases.#1191

Merged
toshihikoyanase merged 57 commits intooptuna:masterfrom
ytsmiling:follow-storage-spec
May 18, 2020
Merged

Increase test coverage of storage tests for single worker cases.#1191
toshihikoyanase merged 57 commits intooptuna:masterfrom
ytsmiling:follow-storage-spec

Conversation

@ytsmiling
Copy link
Copy Markdown
Member

@ytsmiling ytsmiling commented Apr 30, 2020

Motivation

Many storage features/specs are not tested. This low test coverage is a direct cause of the inconsistent implementations among storages. This PR aims to increase the test coverage and, at the same time, remove found bugs/inconsistent behaviors. This PR inevitably relies on #1175 and #1176. While we should test specs related to multi-worker settings, it will make this PR too complicated and it will be separated into another PR.

Description of the changes

  • This PR increases test coverage by adding more cases in tests/test_storage.py. Additionally, this PR resolves many inconsistent behaviors and bugs in the current implementation.
  • This PR slows down the test, which should be resolved by another PR by removing duplicated/redundant methods in the storage class.
  • This PR includes multi-study support from the in-memory storage.
  • This PR changes the interface of testing/StorageSuppliers and related tests. Importantly, this PR removes tests using "common sqlite's db file." Tests related to behaviors in multi-worker settings should be added in other ways by other PRs.

The following space will be used to list all fixed/modified behaviors of storage implementations.

  • Study_id duplication in In-memory DB.
  • Study-name duplication is not handled in in-memory DB.
  • In-meomry DB raises ValueError when deleting non-existent study (expected: KeyError).
  • RDB backend raises ValueError when deleting non-existent study (expected: KeyError).
  • Redis backend raises ValueError when deleting non-existent study (expected: KeyError).
  • In-memory DB raises ValueError when study_id does not exist in get_study_name_from_id (expected: KeyError).
  • RDB backend raises ValueError when study_id does not exist in get_study_name_from_id (expected: KeyError).
  • Redis backend raises ValueError when study_id does not exist in get_study_name_from_id (expected: KeyError).
  • In-memory DB raises ValueError when study_id does not exist in get_study_direction (expected: KeyError).
  • RDB backend raises ValueError when study_id does not exist in get_study_direction (expected: KeyError).
  • Redis backend raises AssertionError when study_id does not exist in get_study_direction (expected: KeyError).
  • In-memory DB does not raise when study_id does not exist in get_study_user_attrs (expected: KeyError).
  • RDB backend raises ValueError when study_id does not exist in get_study_user_attrs (expected: KeyError).
  • Redis backend raises AssertionError when study_id does not exist in get_study_user_attrs (expected: KeyError).
  • In-memory DB does not raise when study_id does not exist in get_study_system_attrs (expected: KeyError).
  • RDB backend raises ValueError when study_id does not exist in get_study_system_attrs (expected: KeyError).
  • Redis backend raises AssertionError when study_id does not exist in get_study_system_attrs (expected: KeyError).
  • In-memory database raises ValueError when creating trial in non-existent study (expected: KeyError).
  • RDB database (sqlite) does not raise when creating trial in non-existent study (expected: KeyError).
  • Redis database raise ValueError when creating trial in non-existent study (expected: KeyError).
  • In-memory database raises IndexError when fetching params of non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when fetching params of non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when fetching params of non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when setting params of non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when setting params of non-existent trials (expected: KeyError).
  • In-memory database raises IndexError when setting values of non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when setting values of non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when setting values of non-existent trials (expected: KeyError).
  • In-memory database raises IndexError when setting intermediate_values of non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when setting intermediate_values of non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when setting intermediate_values of non-existent trials (expected: KeyError).
  • In-memory database raises IndexError when fetching user attributes of non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when fetching user attributes of non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when fetching user attributes of non-existent trials (expected: KeyError).
  • In-memory database raises IndexError when fetching system attributes of non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when fetching system attributes of non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when fetching system attributes of non-existent trials (expected: KeyError).
  • In-memory database raises IndexError when setting system attributes of non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when setting system attributes of non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when setting system attributes of non-existent trials (expected: KeyError).
  • In-memory database raises IndexError when fetching non-existent trials (expected: KeyError).
  • RDB database (sqlite) raises ValueError when fetching non-existent trials (expected: KeyError).
  • Redis database raise AssertionError when fetching non-existent trials (expected: KeyError).
  • Broken get_all_study_summaries in Redis storage.
  • RDB database (sqlite) raises ValueError when counting trials from non-existent study (expected: KeyError).
  • Redis database raise AssertionError when counting trials from non-existent study (expected: KeyError).
  • Broken deep_copy option of get_all_trials in RDB database (sqlite).

Some behaviors which need discussion, but not tackled in this PR.

  • Deleted study_id is reused in RDB backend (sqlite).
  • In-memory database arrows to change RUNNING state into WAITING.
  • RDB database arrows to change RUNNING state into WAITING.
  • Redis database arrows to change RUNNING state into WAITING.
  • Add MySQL to tests.
  • Add PostgreSQL to tests.
  • In-memory database arrows to change state into FINISHED even when the value is not set.
  • RDB database arrows to change state into FINISHED even when the value is not set.
  • Redis database arrows to change state into FINISHED even when the value is not set.
  • In-memory storage became slow due to multi-study support.

@ytsmiling ytsmiling force-pushed the follow-storage-spec branch from 78043d7 to 280c4fb Compare April 30, 2020 04:54
@ytsmiling ytsmiling added bug Issue/PR about behavior that is broken. Not for typos/examples/CI/test but for Optuna itself. optuna.storages Related to the `optuna.storages` submodule. This is automatically labeled by github-actions. optuna.study Related to the `optuna.study` submodule. This is automatically labeled by github-actions. test Unit test. labels Apr 30, 2020
@ytsmiling
Copy link
Copy Markdown
Member Author

Multi-study support will be addressed in #1228 instead of this PR.

@ytsmiling ytsmiling mentioned this pull request May 11, 2020
3 tasks
ytsmiling added a commit to ytsmiling/optuna that referenced this pull request May 11, 2020
ytsmiling added 3 commits May 13, 2020 05:31
# Conflicts:
#	optuna/storages/in_memory.py
#	tests/integration_tests/test_chainermn.py
#	tests/storages_tests/test_storages.py
system_attrs={},
n_trials=0,
datetime_start=datetime.now(),
datetime_start=None,
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: In InMemoryStorage and RDBStorage, the datetime_start is not the time the study created but the time the first trial in the study started.

Comment on lines +341 to +342
if trial.state.is_finished():
self._update_cache(trial_id)
Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These two lines are necessary to manage StudySummaries appropriately.

@@ -119,135 +110,6 @@ def test_set_default_engine_kwargs_for_mysql_with_other_rdb():
assert "pool_pre_ping" not in engine_kwargs


Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comment: Logic tests for RDB storage are merged into tests/storage_tests/test_storages.py.

@codecov-io
Copy link
Copy Markdown

codecov-io commented May 12, 2020

Codecov Report

❗ No coverage uploaded for pull request base (master@e436a84). Click here to learn what that means.
The diff coverage is n/a.

Impacted file tree graph

@@            Coverage Diff            @@
##             master    #1191   +/-   ##
=========================================
  Coverage          ?   86.28%           
=========================================
  Files             ?       92           
  Lines             ?     6781           
  Branches          ?        0           
=========================================
  Hits              ?     5851           
  Misses            ?      930           
  Partials          ?        0           
Impacted Files Coverage Δ
optuna/integration/__init__.py 63.04% <0.00%> (ø)
optuna/storages/rdb/models.py 95.19% <0.00%> (ø)
optuna/integration/lightgbm.py 90.00% <0.00%> (ø)
optuna/trial/_util.py 100.00% <0.00%> (ø)
optuna/multi_objective/samplers/_adapter.py 100.00% <0.00%> (ø)
optuna/integration/chainer.py 80.85% <0.00%> (ø)
optuna/cli.py 32.05% <0.00%> (ø)
optuna/storages/rdb/storage.py 96.06% <0.00%> (ø)
optuna/testing/integration.py 100.00% <0.00%> (ø)
optuna/integration/xgboost.py 86.66% <0.00%> (ø)
... and 82 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update e436a84...e436a84. Read the comment docs.

@sile sile added this to the v1.5.0 milestone May 13, 2020
Copy link
Copy Markdown
Member

@sile sile left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM but I left minor suggestions to make the style of the source code comments align to the Optuna coding convention.

Co-authored-by: Takeru Ohta <phjgt308@gmail.com>

if trial_id not in self._trial_id_to_study_id_and_number:
raise ValueError("No trial with trial_id {} exists.".format(trial_id))
raise KeyError("No trial with trial_id {} exists.".format(trial_id))
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

[Comment] The trial_id is an internal attribute, but I think it is reasonable to use it here because this KeyError is not usually raised by user-code problems.

@toshihikoyanase toshihikoyanase mentioned this pull request May 15, 2020
2 tasks
Copy link
Copy Markdown
Member

@toshihikoyanase toshihikoyanase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for improving the storage tests. It basically looks good to me.
I have small suggestions and a few questions.

Comment on lines +984 to +992
def _check_trial_equality(output: FrozenTrial, expected: FrozenTrial) -> None:
assert output._trial_id == expected._trial_id
assert output.state == expected.state
assert output.value == expected.value
assert output.datetime_start == expected.datetime_start
assert output.datetime_complete == expected.datetime_complete
assert output.user_attrs == expected.user_attrs
assert output.system_attrs == expected.system_attrs
assert output.intermediate_values == expected.intermediate_values
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

assert output == expected is insufficient even if FrozenTrial has the __eq__ method?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems I have misunderstood somethin, and I replaced them with __eq__.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found that for CategoricalDistribution, json_to_distribution(distribution_to_json(dist)) != dist in general and I'll create a PR to add an appropriate eq method to CategoricalDistribution.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll create a PR to add an appropriate eq method to CategoricalDistribution.

Good catch! Thank you.

@ytsmiling ytsmiling requested a review from toshihikoyanase May 18, 2020 00:56
Copy link
Copy Markdown
Member

@toshihikoyanase toshihikoyanase left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM! Thank you for improving the storage tests.

By the way, how about creating issue on the issue on CategoricalDistribution.__eq__ if it takes time to create a PR?

@toshihikoyanase toshihikoyanase merged commit c569c95 into optuna:master May 18, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

bug Issue/PR about behavior that is broken. Not for typos/examples/CI/test but for Optuna itself. optuna.storages Related to the `optuna.storages` submodule. This is automatically labeled by github-actions. optuna.study Related to the `optuna.study` submodule. This is automatically labeled by github-actions. test Unit test.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants