Skip to content
This repository has been archived by the owner on Dec 4, 2024. It is now read-only.

Add unit test for filesystem service. #184

Merged
merged 48 commits into from
Mar 22, 2023
Merged
Show file tree
Hide file tree
Changes from 43 commits
Commits
Show all changes
48 commits
Select commit Hold shift + click to select a range
1c36731
Fixes legacy logger
racheldaniel Nov 18, 2022
652eda7
Initial pass at removing legacy logging
racheldaniel Dec 6, 2022
666e781
Update log file output to use json format
racheldaniel Dec 7, 2022
f9d0c9b
Updates server logging to send events
racheldaniel Dec 7, 2022
ac06e11
Removes outdated comment
racheldaniel Dec 7, 2022
d63a729
Support partial parsing (#151)
racheldaniel Jan 9, 2023
92dd55e
resolves merge conflicts
racheldaniel Jan 9, 2023
23b23f3
Merge branch 'feature/server-on-core-1.5' of github.com:dbt-labs/dbt-…
racheldaniel Jan 9, 2023
ef59eaa
Core integration playground (#129)
ChenyuLInx Jan 12, 2023
52adba7
Merging latest main
racheldaniel Jan 17, 2023
34d3cc4
Upgrade FastAPI version in requirements.txt and add httpx to dev-requ…
jenniferjsmmiller Jan 19, 2023
479d1a4
Accept project path in addition to state_id (#154)
racheldaniel Jan 20, 2023
fc3a38e
Fixes broken tests (#156)
racheldaniel Jan 23, 2023
cec0320
Fix profile for async endpoint (#157)
racheldaniel Jan 27, 2023
b380581
Fixes shutdown and removes middleware
racheldaniel Jan 30, 2023
f2f5279
Fixes response_model as called out by community member on main branch
racheldaniel Jan 30, 2023
b2a88bb
Resolves merge conflicts
racheldaniel Jan 30, 2023
b3ccc38
Sync dbt endpoint (#161)
racheldaniel Feb 1, 2023
11b5ff7
Add task status callback (#164)
jp-dbt Feb 8, 2023
4c85644
make server working with dbt-core main (#167)
ChenyuLInx Feb 14, 2023
fec173e
Control server write locations (#166)
racheldaniel Feb 15, 2023
c90ccb9
Accept a task ID as part of the request and, if present, use it when …
jp-dbt Feb 16, 2023
bd84ae0
Adds error handling for json conversion
racheldaniel Feb 21, 2023
1945b6f
Include all exceptions in error handling. (#169)
dichenqiandbt Feb 23, 2023
8a5318f
Fix bug of not chdir back (#175)
dichenqiandbt Feb 23, 2023
4bcba85
Fix tests. (#173)
dichenqiandbt Feb 23, 2023
64c7732
Merging latest main
racheldaniel Feb 23, 2023
6797958
Update actions (#176)
racheldaniel Feb 27, 2023
6699d43
Removes conditional on test, tailors to branch (#181)
racheldaniel Feb 27, 2023
5d98ba9
fixes formatting
racheldaniel Feb 27, 2023
3f2ee12
fixes formatting
racheldaniel Feb 27, 2023
831cbd2
Testing installations in one line
racheldaniel Feb 27, 2023
07a9256
Undoes consolidaiton to single line
racheldaniel Feb 27, 2023
3809953
Adds quotes to head installs
racheldaniel Feb 27, 2023
428efa4
Add unit test for filesystem service.
dichenqiandbt Feb 28, 2023
0feff31
nit
dichenqiandbt Feb 28, 2023
2b34dc0
Adds 1.5.0b1 to github action
racheldaniel Feb 28, 2023
e675fb6
Adds prerelease flag
racheldaniel Feb 28, 2023
bdd765c
RUNTIME-733 Add smoke tests (#170)
dichenqiandbt Feb 28, 2023
60826ec
Fixes linting
racheldaniel Feb 28, 2023
5b206b8
Merge branch 'feature/v0.2.0' of https://github.com/dbt-labs/dbt-serv…
dichenqiandbt Feb 28, 2023
a3e053d
Merge branch 'main' of https://github.com/dbt-labs/dbt-server into di…
dichenqiandbt Feb 28, 2023
125635b
format
dichenqiandbt Mar 1, 2023
1b08ccc
Update dbt_server/services/filesystem_service.py
dichenqiandbt Mar 3, 2023
c9edfbe
Update dbt_server/services/filesystem_service.py
dichenqiandbt Mar 3, 2023
8f277ad
Update dbt_server/services/filesystem_service.py
dichenqiandbt Mar 3, 2023
06732a8
Fix comment
dichenqiandbt Mar 3, 2023
63986c8
Merge branch 'main' of https://github.com/dbt-labs/dbt-server into di…
dichenqiandbt Mar 3, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 93 additions & 15 deletions dbt_server/services/filesystem_service.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,19 +11,51 @@
# This is defined in dbt-core-- dir path is configurable but not filename
DBT_LOG_FILE_NAME = "dbt.log"

# File system tree structure.
# root_path(dbt project)

# target_path
# |
# - partial_parse_path(partial_parse.msgpack)

# working_dir
# |
# - task_artifacts_path
# | |
# | - log_path(dbt.log)
# |
# - db_path(sqlite)
# |
# - latest_state_file_path
# |
# - latest_project_path_file_path


def get_working_dir():
"""Returns dbt-server working directory which has dbt-server generated
files."""
return os.environ.get("__DBT_WORKING_DIR", DEFAULT_WORKING_DIR)


def get_target_path():
"""Returns dbt-core compiled target path."""
# TODO: The --target-path flag should override this, but doesn't
# appear to be working on invoke. When it does, need to revisit
# how partial parsing is working
return os.environ.get("DBT_TARGET_PATH", DEFAULT_TARGET_DIR)


def get_root_path(state_id=None, project_path=None):
def get_root_path(state_id: str = None, project_path: str = None):
"""Returns root path of dbt project. Only one of `state_id` and
`project_path` should be passed in. If both arguments are None, returns
None.

Args:
state_id: if set, we infer the dbt project is not stored locally,
instead it's pushed by client. Hence root path is a temp directory
that stores pushed dbt project.
project_path: if set, we infer the dbt project is stored in a local
fixed directory which is the root path."""
if project_path is not None:
return os.path.abspath(project_path)
if state_id is None:
Expand All @@ -33,35 +65,49 @@ def get_root_path(state_id=None, project_path=None):


def get_task_artifacts_path(task_id, state_id=None):
"""Returns artifacts path of dbt-core async style invocation.
Args:
task_id: identify which async task the log file belongs to.
state_id: optional, only used for pushed style dbt project."""
working_dir = get_working_dir()
if state_id is None:
return os.path.join(working_dir, task_id)
return os.path.join(working_dir, f"state-{state_id}", task_id)


def get_log_path(task_id, state_id=None):
"""Returns path of dbt-core generated log file for async style invocation.

Args:
task_id: identify which async task the log file belongs to.
state_id: optional, only used for pushed style dbt project."""
artifacts_path = get_task_artifacts_path(task_id, state_id)
return os.path.join(artifacts_path, DBT_LOG_FILE_NAME)


def get_partial_parse_path():
"""Returns dbt-core compiled partial parse file."""
target_path = get_target_path()
return os.path.join(target_path, PARTIAL_PARSE_FILE)


def get_db_path():
"""Returns local metadata database data file path. Creates directory if
not existed."""
working_dir = get_working_dir()
path = os.path.join(working_dir, DATABASE_FILE_NAME)
ensure_dir_exists(path)
_ensure_dir_exists(path)
return path


def get_latest_state_file_path():
"""Returns local recorded dbt-server lastest state id file path."""
working_dir = get_working_dir()
return os.path.join(working_dir, "latest-state-id.txt")


def get_latest_project_path_file_path():
"""Returns local recorded dbt-server lastest project path file path."""
working_dir = get_working_dir()
return os.path.join(working_dir, "latest-project-path.txt")

Expand All @@ -71,20 +117,25 @@ def get_path(*path_parts):


@tracer.wrap
def get_size(path):
def get_size(path: str):
"""Returns file size specified by `path`."""
return os.path.getsize(path)


@tracer.wrap
def ensure_dir_exists(path):
def _ensure_dir_exists(path: str):
"""Check directory of `path` exists, if not make new directory
recursively."""
dirname = os.path.dirname(path)
if not os.path.exists(dirname):
os.makedirs(dirname)


@tracer.wrap
def write_file(path, contents):
ensure_dir_exists(path)
def write_file(path: str, contents: str):
"""Writes `contents` encoded as utf-8 into `path`. The direcory of `path`
will be created recursively if not existed."""
_ensure_dir_exists(path)

with open(path, "wb") as fh:
if isinstance(contents, str):
Expand All @@ -93,13 +144,20 @@ def write_file(path, contents):


@tracer.wrap
def copy_file(source_path, dest_path):
ensure_dir_exists(dest_path)
def copy_file(source_path: str, dest_path: str):
"""Copies file from `source_path` to `dest_path`. The direcory of
`dest_path` will be created recursively if not existed."""
_ensure_dir_exists(dest_path)
shutil.copyfile(source_path, dest_path)


@tracer.wrap
def read_serialized_manifest(path):
def read_serialized_manifest(path: str):
"""Returns serialized manifest file from `path`.

Raises:
StateNotFoundException: if file is not found.
"""
try:
with open(path, "rb") as fh:
return fh.read()
Expand All @@ -108,7 +166,17 @@ def read_serialized_manifest(path):


@tracer.wrap
def write_unparsed_manifest_to_disk(state_id, previous_state_id, filedict):
def write_unparsed_manifest_to_disk(
state_id: str, previous_state_id: str, filedict: dict
):
"""Writes files in `filedict` to root path specified by `state_id`, then
copies previous partial parsed msgpack to current root path.

Args:
state_id: required to get root path.
previous_state_id: if it's none, we'll skip copy previous partial parsed
msgpack to current root path.
filedict: key is file name and value is file_info."""
root_path = get_root_path(state_id)
if os.path.exists(root_path):
shutil.rmtree(root_path)
Expand All @@ -131,7 +199,13 @@ def write_unparsed_manifest_to_disk(state_id, previous_state_id, filedict):


@tracer.wrap
def get_latest_state_id(state_id):
def get_latest_state_id(state_id: str):
"""Returns dbt-server latest processed state id.

Args:
state_id: if `state_id` is none, returns state id from local persisted
storage, otherwise returns `state_id` directly.
"""
if not state_id:
path = os.path.abspath(get_latest_state_file_path())
if not os.path.exists(path):
Expand All @@ -143,6 +217,8 @@ def get_latest_state_id(state_id):

@tracer.wrap
def get_latest_project_path():
"""Returns dbt-server latest processed project path, read from local
persisted storage. Returns None if not found."""
path = os.path.abspath(get_latest_project_path_file_path())
if not os.path.exists(path):
return None
Expand All @@ -152,16 +228,18 @@ def get_latest_project_path():


@tracer.wrap
def update_state_id(state_id):
def update_state_id(state_id: str):
"""Updates local persisted `state_id`."""
path = os.path.abspath(get_latest_state_file_path())
ensure_dir_exists(path)
_ensure_dir_exists(path)
with open(path, "w+") as latest_path_file:
latest_path_file.write(state_id)


@tracer.wrap
def update_project_path(project_path):
def update_project_path(project_path: str):
"""Updates local persisted `project_path`."""
path = os.path.abspath(get_latest_project_path_file_path())
ensure_dir_exists(path)
_ensure_dir_exists(path)
with open(path, "w+") as latest_path_file:
latest_path_file.write(project_path)
Loading