Skip to content
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
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
12 changes: 10 additions & 2 deletions lib/fixture_kit/cache.rb
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ def load
raise FixtureKit::CacheMissingError, "Cache does not exist for fixture '#{fixture.identifier}'"
end

@content ||= file_cache.read
read_content

FixtureKit.runner.coders.each do |coder|
coder.mount(content.data_for(coder.class))
Expand All @@ -49,6 +49,14 @@ def load
Repository.new(content.exposed)
end

# Lazily loads @content from the file cache. Used when content is needed in
# memory without a full mount (e.g. when a child fixture is being saved and
# needs the parent's coder data, while the parent itself was already cached
# to disk in a previous process and has not yet been mounted).
def read_content
@content ||= file_cache.read
end

def save
FixtureKit.runner.adapter.execute do |context|
@content = MemoryCache.new(
Expand All @@ -68,7 +76,7 @@ def evaluate(coders, context, data = {}, &block)
else
coder, *remaining_coders = coders

parent_data = fixture.parent ? fixture.parent.cache.content.data_for(coder.class) : nil
parent_data = fixture.parent&.cache&.read_content&.data_for(coder.class)
Comment thread
navidemad marked this conversation as resolved.
Outdated
data[coder.class] = coder.generate(parent_data: parent_data) do
evaluate(remaining_coders, context, data, &block)
end
Expand Down
43 changes: 42 additions & 1 deletion spec/unit/fixture_cache_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -231,7 +231,7 @@ def identifier_for(identifier)
data: { FixtureKit::ActiveRecordCoder => { User => nil } },
exposed: {}
)
parent_cache = instance_double(FixtureKit::Cache, content: parent_cache_data)
parent_cache = instance_double(FixtureKit::Cache, read_content: parent_cache_data)
parent_fixture = instance_double(FixtureKit::Fixture, cache: parent_cache)
allow(parent_fixture).to receive(:mount) do
User.create!(name: "Parent Owner", email: "parent-owner@example.com")
Expand All @@ -256,6 +256,47 @@ def identifier_for(identifier)
data = JSON.parse(File.read(child_cache.path))
expect(data["data"]["FixtureKit::ActiveRecordCoder"].keys).to include("User", "Project")
end

it "loads parent content from disk when child saves without parent in memory" do
# Reproduit le scénario "data_for for nil" : un fixture parent a déjà
# été persisté sur disque (process précédent), puis un fixture enfant
# doit être généré dans un nouveau process où parent.cache.content est nil.
parent_definition = FixtureKit::Definition.new do
User.create!(name: "Parent Owner", email: "parent-owner-cross-process@example.com")
end
parent_fixture = instance_double(
FixtureKit::Fixture,
identifier: "parent_fixture",
definition: parent_definition,
parent: nil
)
parent_cache = described_class.new(parent_fixture)
parent_cache.save
parent_cache.clear_memory # simule un nouveau process : @content = nil mais le fichier existe

allow(parent_fixture).to receive(:cache).and_return(parent_cache)
allow(parent_fixture).to receive(:mount) do
User.create!(name: "Parent Owner", email: "parent-owner-cross-process@example.com")
FixtureKit::Repository.new({})
end

child_definition = FixtureKit::Definition.new do
owner = User.find_by!(email: "parent-owner-cross-process@example.com")
Project.create!(name: "Cross-process project", owner: owner)
end
child_fixture = instance_double(
FixtureKit::Fixture,
identifier: "child_fixture",
definition: child_definition,
parent: parent_fixture
)
child_cache = described_class.new(child_fixture)

expect { child_cache.save }.not_to raise_error

data = JSON.parse(File.read(child_cache.path))
expect(data["data"]["FixtureKit::ActiveRecordCoder"].keys).to include("User", "Project")
end
end

describe "#clear_memory" do
Expand Down