Updating an Ecto record succeeds but subsequent fetches show old data in tests

Hi all,

I have a record which I am updating using a multi, and I can get the successful return value from my function. My issue is that any following reads to the database show that the old value is still present. My understanding was that the tests run in a transaction, and all database data is available to the same processes? I have not used a different process anywhere as far as I can see. I also tried with async: true and also false. I also tried adding read_after_writes: true to the schema, and I tried adding returning: true and force: true to the Multi.update call.

Here’s my code from my tests:

      {:ok, %{job: job}} = Subject.update_job(job, %{status: "draft"})
      IO.inspect({job.id, job.status})

      Repo.one(from(j in HiredHippo.Jobs.Job, where: j.id == ^job.id, select: j.status))
      |> IO.inspect()

      HiredHippo.Recommendations.JobRecommendation
      |> join(:inner, [jr], j in assoc(jr, :job))
      |> where(
        [jr, j],
        not jr.expired and not job_application_exists(jr.candidate_id, jr.job_id, "readd") and
          jr.match_percentage >= ^HiredHippo.Recommendations.MatchPercentage.base_match() and
          j.status == "published" and not j.archived
      )
      |> select([jr, j], {jr.id, j.id, jr.expired, j.archived, j.status})
      |> Repo.all()
      |> IO.inspect()

What I am seeing, is that the first inspect shows that the return value from update_job/2 includes "draft", but the two following inspects show that the job status is "published". This is causing my test to fail later on.

So can anyone think of why the return value shows one thing and following reads show something else? I’m quite stumped here.

What SQL is sent to the database? (try turning the log level up to debug to see it in the console)

It sounds like update_job is somehow returning an unsaved record, but it’s hard to be sure without logs or source code.

Aha! Figured it out, thanks for the pointer. Above the code I had shared, I was creating the job, then publishing it, and then the first line of the code I shared was the update to put it in draft again. So the update to put it in draft again was never firing because the result from the publish was not saved.

So the solution was to change this

    test "removes jobs from a candidate's feed when job is paused", %{job: job} do
      candidate = CandidateFixture.create()
      Preferences.set_notification_preferences(candidate, %{candidate_searchable: true})
      Subject.publish_job(job)
      JobInteractions.invite_candidate_to_job(candidate, job.id)
      assert Recommendations.pending_recommendation_exists?(candidate.id, job.id)
      Subject.update_job(job, %{status: "draft"})
      refute Recommendations.pending_recommendation_exists?(candidate.id, job.id)
    end

to this

    test "removes jobs from a candidate's feed when job is paused", %{job: job} do
      candidate = CandidateFixture.create()
      Preferences.set_notification_preferences(candidate, %{candidate_searchable: true})
      {:ok, %{job: job}} = Subject.publish_job(job)
      JobInteractions.invite_candidate_to_job(candidate, job.id)
      assert Recommendations.pending_recommendation_exists?(candidate.id, job.id)
      Subject.update_job(job, %{status: "draft"})
      refute Recommendations.pending_recommendation_exists?(candidate.id, job.id)
    end