summaryrefslogtreecommitdiffstats
path: root/Tests/ExternalProjectUpdate/ExternalProjectUpdateTest.cmake
blob: 96dca38874213e4c10cf863507e685a3b9827a7d (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
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
# Set the ExternalProject GIT_TAG to desired_tag, and make sure the
# resulting checked out version is resulting_sha and rebuild.
# This check's the correct behavior of the ExternalProject UPDATE_COMMAND.
# Also verify that a fetch only occurs when fetch_expected_tsX is 1.
macro(check_a_tag
  desired_tag
  resulting_sha
  fetch_expected_ts1  # TutorialStep1-GIT
  fetch_expected_ts2  # TutorialStep2-GIT
  update_strategy
)
  message( STATUS "Checking ExternalProjectUpdate to tag: ${desired_tag}" )

  # Remove the FETCH_HEAD file, so we can check if it gets replaced with a 'git
  # fetch'.
  set( FETCH_HEAD_file ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT/.git/FETCH_HEAD )
  file( REMOVE ${FETCH_HEAD_file} )

  # Give ourselves a marker in the output. It is difficult to tell where we
  # are up to without this
  message(STATUS "===> check_a_tag: "
    "${desired_tag} ${resulting_sha} "
    "${fetch_expected_ts1} ${fetch_expected_ts2} "
    "${update_strategy}"
  )

  # Configure
  execute_process(COMMAND ${CMAKE_COMMAND}
    -G ${CMAKE_GENERATOR} -T "${CMAKE_GENERATOR_TOOLSET}"
    -A "${CMAKE_GENERATOR_PLATFORM}"
    -DTEST_GIT_TAG:STRING=${desired_tag}
    -DCMAKE_EP_GIT_REMOTE_UPDATE_STRATEGY:STRING=${update_strategy}
    ${ExternalProjectUpdate_SOURCE_DIR}
    WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}
    RESULT_VARIABLE error_code
    )
  if(error_code)
    message(FATAL_ERROR "Could not configure the project.")
  endif()

  # Build
  execute_process(COMMAND ${CMAKE_COMMAND}
    --build ${ExternalProjectUpdate_BINARY_DIR}
    RESULT_VARIABLE error_code
    )
  if(error_code)
    message(FATAL_ERROR "Could not build the project.")
  endif()

  # Check the resulting SHA
  execute_process(COMMAND ${GIT_EXECUTABLE}
    rev-list --max-count=1 HEAD
    WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
    RESULT_VARIABLE error_code
    OUTPUT_VARIABLE tag_sha
    OUTPUT_STRIP_TRAILING_WHITESPACE
    )
  if(error_code)
    message(FATAL_ERROR "Could not check the sha.")
  endif()

  if(NOT (${tag_sha} STREQUAL ${resulting_sha}))
    message(FATAL_ERROR "UPDATE_COMMAND produced
  ${tag_sha}
when
  ${resulting_sha}
was expected."
    )
  endif()

  if( NOT EXISTS ${FETCH_HEAD_file} AND ${fetch_expected_ts1})
    message( FATAL_ERROR "Fetch did NOT occur when it was expected.")
  endif()
  if( EXISTS ${FETCH_HEAD_file} AND NOT ${fetch_expected_ts1})
    message( FATAL_ERROR "Fetch DID occur when it was not expected.")
  endif()

  message( STATUS "Checking ExternalProjectUpdate to tag: ${desired_tag} (disconnected)" )

  # Remove the FETCH_HEAD file, so we can check if it gets replaced with a 'git
  # fetch'.
  set( FETCH_HEAD_file ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT/.git/FETCH_HEAD )
  file( REMOVE ${FETCH_HEAD_file} )

  # Check initial SHA
  execute_process(COMMAND ${GIT_EXECUTABLE}
    rev-list --max-count=1 HEAD
    WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT
    RESULT_VARIABLE error_code
    OUTPUT_VARIABLE initial_sha
    OUTPUT_STRIP_TRAILING_WHITESPACE
    )

  # Configure
  execute_process(COMMAND ${CMAKE_COMMAND}
    -G ${CMAKE_GENERATOR} -T "${CMAKE_GENERATOR_TOOLSET}"
    -A "${CMAKE_GENERATOR_PLATFORM}"
    -DTEST_GIT_TAG:STRING=${desired_tag}
    ${ExternalProjectUpdate_SOURCE_DIR}
    WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}
    RESULT_VARIABLE error_code
    )
  if(error_code)
    message(FATAL_ERROR "Could not configure the project.")
  endif()

  # Build
  execute_process(COMMAND ${CMAKE_COMMAND}
    --build ${ExternalProjectUpdate_BINARY_DIR}
    RESULT_VARIABLE error_code
    )
  if(error_code)
    message(FATAL_ERROR "Could not build the project.")
  endif()

  if( EXISTS ${FETCH_HEAD_file} )
    message( FATAL_ERROR "Fetch occurred when it was not expected.")
  endif()

  # Check the resulting SHA
  execute_process(COMMAND ${GIT_EXECUTABLE}
    rev-list --max-count=1 HEAD
    WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT
    RESULT_VARIABLE error_code
    OUTPUT_VARIABLE tag_sha
    OUTPUT_STRIP_TRAILING_WHITESPACE
    )
  if(error_code)
    message(FATAL_ERROR "Could not check the sha.")
  endif()

  if(NOT (${tag_sha} STREQUAL ${initial_sha}))
    message(FATAL_ERROR "Update occurred when it was not expected.")
  endif()

  # Update
  execute_process(COMMAND ${CMAKE_COMMAND}
    --build ${ExternalProjectUpdate_BINARY_DIR}
    --target TutorialStep2-GIT-update
    RESULT_VARIABLE error_code
    )
  if(error_code)
    message(FATAL_ERROR "Could not build the project.")
  endif()

  # Check the resulting SHA
  execute_process(COMMAND ${GIT_EXECUTABLE}
    rev-list --max-count=1 HEAD
    WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep2-GIT
    RESULT_VARIABLE error_code
    OUTPUT_VARIABLE tag_sha
    OUTPUT_STRIP_TRAILING_WHITESPACE
    )
  if(error_code)
    message(FATAL_ERROR "Could not check the sha.")
  endif()

  if(NOT (${tag_sha} STREQUAL ${resulting_sha}))
    message(FATAL_ERROR "UPDATE_COMMAND produced
  ${tag_sha}
when
  ${resulting_sha}
was expected."
    )
  endif()

  if( NOT EXISTS ${FETCH_HEAD_file} AND ${fetch_expected_ts2})
    message( FATAL_ERROR "Fetch did NOT occur when it was expected.")
  endif()
  if( EXISTS ${FETCH_HEAD_file} AND NOT ${fetch_expected_ts2})
    message( FATAL_ERROR "Fetch DID occur when it was not expected.")
  endif()
endmacro()

find_package(Git)
set(do_git_tests 0)
if(GIT_EXECUTABLE)
  set(do_git_tests 1)

  message(STATUS "GIT_VERSION_STRING='${GIT_VERSION_STRING}'")

  if("${GIT_VERSION_STRING}" VERSION_LESS 1.6.5)
    message(STATUS "No ExternalProject git tests with git client less than version 1.6.5")
    set(do_git_tests 0)
  endif()
endif()

# When re-running tests locally, this ensures we always start afresh
file(REMOVE_RECURSE ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals)

if(do_git_tests)
  check_a_tag(origin/master b5f0fc2d442b72dd29e655c329af0062e1f8d129 1 1 REBASE)
  check_a_tag(tag1          4209914b424925d6f1b558d79454d60967d4b0f3 1 0 REBASE)
  # With the Git UPDATE_COMMAND performance patch, this will not require a
  # 'git fetch'
  check_a_tag(tag1          4209914b424925d6f1b558d79454d60967d4b0f3 0 0 REBASE)
  check_a_tag(tag2          ae72641040f1c9512f152d08afb6909f0498f958 1 0 REBASE)
  check_a_tag(4209914b42    4209914b424925d6f1b558d79454d60967d4b0f3 0 0 REBASE)
  check_a_tag(origin/master b5f0fc2d442b72dd29e655c329af0062e1f8d129 1 1 REBASE)
  # This is a remote symbolic ref, so it will always trigger a 'git fetch'
  check_a_tag(origin/master b5f0fc2d442b72dd29e655c329af0062e1f8d129 1 1 REBASE)

  foreach(strategy IN ITEMS CHECKOUT REBASE_CHECKOUT)
    # Move local master back, then apply a change that will cause a conflict
    # during rebase
    execute_process(COMMAND ${GIT_EXECUTABLE} checkout master
      WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
      RESULT_VARIABLE error_code
      )
    if(error_code)
      message(FATAL_ERROR "Could not reset local master back to tag1.")
    endif()
    execute_process(COMMAND ${GIT_EXECUTABLE} reset --hard tag1
      WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
      RESULT_VARIABLE error_code
      )
    if(error_code)
      message(FATAL_ERROR "Could not reset local master back to tag1.")
    endif()

    set(cmlFile ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT/CMakeLists.txt)
    file(READ ${cmlFile} contents)
    string(REPLACE "find TutorialConfig.h" "find TutorialConfig.h (conflict here)"
      conflictingContent "${contents}"
      )
    file(WRITE ${cmlFile} "${conflictingContent}")
    execute_process(COMMAND ${GIT_EXECUTABLE} commit -a -m "This should cause a conflict"
      WORKING_DIRECTORY ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT
      RESULT_VARIABLE error_code
      )
    if(error_code)
      message(FATAL_ERROR "Could not commit conflicting change.")
    endif()
    # This should discard our commit but leave behind an annotated tag
    check_a_tag(origin/master b5f0fc2d442b72dd29e655c329af0062e1f8d129 1 1 ${strategy})
  endforeach()

  # This file matches a .gitignore rule that the last commit defines. We can't
  # directly check that updates don't stash ignored contents because the stash
  # and pop are both done within the update step. We don't have an opportunity
  # to check things in between, but we can at least check that the update step
  # doesn't choke on it.
  set(ignoredFile ${ExternalProjectUpdate_BINARY_DIR}/CMakeExternals/Source/TutorialStep1-GIT/ignored_item)
  file(TOUCH ${ignoredFile})
  check_a_tag(origin/master b5f0fc2d442b72dd29e655c329af0062e1f8d129 1 1 REBASE)
  if(NOT EXISTS ${ignoredFile})
    message(FATAL_ERROR "Ignored file is missing")
  endif()

endif()