summaryrefslogtreecommitdiff
path: root/spec/lib/gitlab/diff/highlight_cache_spec.rb
blob: 6dabfd0ef2cb798b0980c0016767912d7b706d2b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
# frozen_string_literal: true

require 'spec_helper'

describe Gitlab::Diff::HighlightCache, :clean_gitlab_redis_cache do
  let(:merge_request) { create(:merge_request_with_diffs) }
  let(:diff_hash) do
    { ".gitignore-false-false-false" =>
      [{ line_code: nil, rich_text: nil, text: "@@ -17,3 +17,4 @@ rerun.txt", type: "match", index: 0, old_pos: 17, new_pos: 17 },
       { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_17_17",
        rich_text: " <span id=\"LC17\" class=\"line\" lang=\"plaintext\">pickle-email-*.html</span>\n",
        text: " pickle-email-*.html",
        type: nil,
        index: 1,
        old_pos: 17,
        new_pos: 17 },
       { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_18_18",
        rich_text: " <span id=\"LC18\" class=\"line\" lang=\"plaintext\">.project</span>\n",
        text: " .project",
        type: nil,
        index: 2,
        old_pos: 18,
        new_pos: 18 },
       { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_19_19",
        rich_text: " <span id=\"LC19\" class=\"line\" lang=\"plaintext\">config/initializers/secret_token.rb</span>\n",
        text: " config/initializers/secret_token.rb",
        type: nil,
        index: 3,
        old_pos: 19,
        new_pos: 19 },
       { line_code: "a5cc2925ca8258af241be7e5b0381edf30266302_20_20",
        rich_text: "+<span id=\"LC20\" class=\"line\" lang=\"plaintext\">.DS_Store</span>",
        text: "+.DS_Store",
        type: "new",
        index: 4,
        old_pos: 20,
        new_pos: 20 }] }
  end

  let(:cache_key) { cache.key }

  subject(:cache) { described_class.new(merge_request.diffs) }

  describe '#decorate' do
    # Manually creates a Diff::File object to avoid triggering the cache on
    # the FileCollection::MergeRequestDiff
    let(:diff_file) do
      diffs = merge_request.diffs
      raw_diff = diffs.diffable.raw_diffs(diffs.diff_options.merge(paths: ['CHANGELOG'])).first
      Gitlab::Diff::File.new(raw_diff,
                             repository: diffs.project.repository,
                             diff_refs: diffs.diff_refs,
                             fallback_diff_refs: diffs.fallback_diff_refs)
    end

    it 'does not calculate highlighting when reading from cache' do
      cache.write_if_empty
      cache.decorate(diff_file)

      expect_any_instance_of(Gitlab::Diff::Highlight).not_to receive(:highlight)

      diff_file.highlighted_diff_lines
    end

    it 'assigns highlighted diff lines to the DiffFile' do
      cache.write_if_empty
      cache.decorate(diff_file)

      expect(diff_file.highlighted_diff_lines.size).to be > 5
    end
  end

  describe '#write_if_empty' do
    it 'filters the key/value list of entries to be caches for each invocation' do
      paths = merge_request.diffs.diff_files.select(&:text?).map(&:file_path)

      expect(cache).to receive(:write_to_redis_hash)
        .with(hash_including(*paths))
        .once
        .and_call_original

      2.times { cache.write_if_empty }
    end

    it 'reads from cache once' do
      expect(cache).to receive(:read_cache).once.and_call_original

      cache.write_if_empty
    end

    context 'different diff_collections for the same diffable' do
      before do
        cache.write_if_empty
      end

      it 'writes an uncached files in the collection to the same redis hash' do
        Gitlab::Redis::Cache.with { |r| r.hdel(cache_key, "files/whitespace") }

        expect { cache.write_if_empty }
          .to change { Gitlab::Redis::Cache.with { |r| r.hgetall(cache_key) } }
      end
    end
  end

  describe '#write_to_redis_hash' do
    it 'creates or updates a Redis hash' do
      expect { cache.send(:write_to_redis_hash, diff_hash) }
        .to change { Gitlab::Redis::Cache.with { |r| r.hgetall(cache_key) } }
    end

    # Note that this spec and the code it confirms can be removed when
    #   :hset_redis_diff_caching is fully launched.
    #
    it 'attempts to clear deprecated cache entries' do
      expect_any_instance_of(Gitlab::Diff::DeprecatedHighlightCache)
        .to receive(:clear).and_call_original

      cache.send(:write_to_redis_hash, diff_hash)
    end
  end

  describe '#clear' do
    it 'clears cache' do
      expect_any_instance_of(Redis).to receive(:del).with(cache_key)

      cache.clear
    end
  end
end