Really fix regression introduced in 23879bc (fixes #2220)

This commit is contained in:
Ryan Lue 2018-09-04 11:49:44 +02:00
parent 19319d9d83
commit b58fcbb5fc
12 changed files with 23836 additions and 58 deletions

View file

@ -164,8 +164,9 @@ group :development, :test do
# mock http calls # mock http calls
gem 'webmock' gem 'webmock'
# record and replay TCP transactions # record and replay TCP/HTTP transactions
gem 'tcr' gem 'tcr'
gem 'vcr'
end end
# Want to extend Zammad with additional gems? # Want to extend Zammad with additional gems?

View file

@ -461,6 +461,7 @@ GEM
valid_email2 (2.1.0) valid_email2 (2.1.0)
activemodel (>= 3.2) activemodel (>= 3.2)
mail (~> 2.5) mail (~> 2.5)
vcr (4.0.0)
viewpoint (1.1.0) viewpoint (1.1.0)
httpclient httpclient
logging logging
@ -565,6 +566,7 @@ DEPENDENCIES
uglifier uglifier
unicorn unicorn
valid_email2 valid_email2
vcr
viewpoint viewpoint
webmock webmock
writeexcel writeexcel

View file

@ -25,8 +25,7 @@ module Import
end end
def find(id) def find(id)
(@lookup_map[id] ||= @connection.get_folder(id)) || @lookup_map[id] ||= @connection.get_folder(id)
id_folder_map[id]
end end
def all def all
@ -43,8 +42,8 @@ module Import
end end
def display_path(folder) def display_path(folder)
display_name = folder.display_name&.utf8_encode(fallback: :read_as_sanitized_binary) display_name = folder.display_name.utf8_encode(fallback: :read_as_sanitized_binary)
parent_folder = find(folder.parent_folder_id) parent_folder = id_folder_map[folder.parent_folder_id]
return display_name if parent_folder.blank? return display_name if parent_folder.blank?

View file

@ -2,81 +2,74 @@ require 'rails_helper'
RSpec.describe Import::Exchange::Folder do RSpec.describe Import::Exchange::Folder do
# see https://github.com/zammad/zammad/issues/2152 # see https://github.com/zammad/zammad/issues/2152
# WARNING! This test is closely tied to the implementation. :(
describe '#display_path (#2152)' do describe '#display_path (#2152)' do
let(:subject) { described_class.new(connection) } let(:subject) { described_class.new(ews_connection) }
let(:connection) { instance_double('Viewpoint::EWSClient') } let(:ews_connection) { Viewpoint::EWSClient.new(endpoint, user, pass) }
let(:root_folder) { double('EWS Folder') } let(:endpoint) { 'https://exchange.example.com/EWS/Exchange.asmx' }
let(:child_folder) { double('EWS Folder') } let(:user) { 'user@example.com' }
let(:exception_case) { double('EWS Folder') } let(:pass) { 'password' }
let(:grandchild_of_root) { ews_connection.get_folder_by_name('Inbox') }
let(:child_of_root) { ews_connection.get_folder(grandchild_of_root.parent_folder_id) }
context 'when folder.display_name returns nil' do around do |example|
before do cassette_name = example.description.gsub(/[^0-9A-Za-z.\-]+/, '_')
allow(root_folder).to receive(:display_name).and_return(nil) VCR.use_cassette("lib/import/exchange/folder/#{cassette_name}") { example.run }
allow(root_folder).to receive(:parent_folder_id).and_return(nil)
allow(subject).to receive(:find).with(any_args).and_return(root_folder)
allow(subject).to receive(:find).with(nil).and_return(nil)
end
it 'returns nil' do
expect(subject.display_path(root_folder)).to be(nil)
end
end end
context 'when server returns valid UTF-8' do context 'when server returns valid UTF-8' do
before do context 'and target folder is in root directory' do
allow(root_folder).to receive(:display_name).and_return('Root')
allow(root_folder).to receive(:parent_folder_id).and_return(nil)
allow(child_folder).to receive(:display_name).and_return('Leaf')
allow(child_folder).to receive(:parent_folder_id).and_return(1)
allow(exception_case).to receive(:display_name).and_return('Error-Raising Leaf')
allow(exception_case).to receive(:parent_folder_id).and_raise(Viewpoint::EWS::EwsError)
allow(subject).to receive(:find).with(any_args).and_return(root_folder)
allow(subject).to receive(:find).with(nil).and_return(nil)
end
context 'and target folder is directory root' do
it 'returns the display name of the folder' do it 'returns the display name of the folder' do
expect(subject.display_path(root_folder)).to eq('Root') expect(subject.display_path(child_of_root))
.to eq('Top of Information Store')
end end
end end
context 'and target folder is NOT directory root' do context 'and target folder is in subfolder of root' do
it 'returns the full path from root to target' do it 'returns the full path from root to target' do
expect(subject.display_path(child_folder)).to eq('Root -> Leaf') expect(subject.display_path(grandchild_of_root))
.to eq('Top of Information Store -> Inbox')
end end
end end
context 'and walking up directory tree raises EwsError' do context 'and walking up directory tree raises EwsError' do
it 'returns the partial path from error to target folder' do it 'returns the partial path from error to target folder' do
expect(subject.display_path(exception_case)).to eq('Error-Raising Leaf') allow(subject)
.to receive(:id_folder_map).with(any_args).and_raise(Viewpoint::EWS::EwsError)
expect(subject.display_path(grandchild_of_root))
.to eq('Inbox')
end end
end end
end end
context 'when server returns invalid UTF-8' do context 'when server returns invalid UTF-8' do
before do context 'and target folder is in root directory' do
allow(root_folder).to receive(:display_name).and_return('你好'.b) it 'returns the display name of the folder in valid UTF-8' do
allow(root_folder).to receive(:parent_folder_id).and_return(nil) allow(child_of_root)
.to receive(:display_name).and_return('你好'.b)
allow(child_folder).to receive(:display_name).and_return('你好'.b) expect { subject.display_path(child_of_root).to_json }.not_to raise_error
allow(child_folder).to receive(:parent_folder_id).and_return(1) end
allow(exception_case).to receive(:display_name).and_return('你好'.b)
allow(exception_case).to receive(:parent_folder_id).and_raise(Viewpoint::EWS::EwsError)
allow(subject).to receive(:find).with(any_args).and_return(root_folder)
allow(subject).to receive(:find).with(nil).and_return(nil)
end end
it 'returns a valid UTF-8 string' do context 'and target folder is in subfolder of root' do
expect { subject.display_path(root_folder).to_json }.not_to raise_error it 'returns the full path from root to target in valid UTF-8' do
expect { subject.display_path(child_folder).to_json }.not_to raise_error allow(grandchild_of_root)
expect { subject.display_path(exception_case).to_json }.not_to raise_error .to receive(:display_name).and_return('你好'.b)
expect { subject.display_path(grandchild_of_root).to_json }.not_to raise_error
end
end
context 'and walking up directory tree raises EwsError' do
it 'returns the partial path from error to target folder in valid UTF-8' do
allow(grandchild_of_root)
.to receive(:display_name).and_return('你好'.b)
allow(subject)
.to receive(:id_folder_map).with(any_args).and_raise(Viewpoint::EWS::EwsError)
expect { subject.display_path(grandchild_of_root).to_json }.not_to raise_error
end
end end
end end
end end

5
spec/support/vcr.rb Normal file
View file

@ -0,0 +1,5 @@
VCR.configure do |config|
config.cassette_library_dir = 'test/data/vcr_cassettes'
config.hook_into :webmock
config.allow_http_connections_when_no_cassette = true
end

View file

@ -2,7 +2,7 @@
# - Zammad webservices # - Zammad webservices
# - Google (calendar) # - Google (calendar)
allowed_sites = lambda do |uri| allowed_sites = lambda do |uri|
['zammad.com', 'google.com'].any? do |site| ['zammad.com', 'google.com', 'exchange.example.com'].any? do |site|
uri.host.include?(site) uri.host.include?(site)
end end
end end

View file

@ -0,0 +1,97 @@
---
http_interactions:
- request:
method: post
uri: https://exchange.example.com/EWS/Exchange.asmx
body:
encoding: UTF-8
string: |
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<soap:Header>
<t:RequestServerVersion Version="Exchange2010"/>
</soap:Header>
<soap:Body>
<FindFolder xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" Traversal="Shallow">
<FolderShape>
<t:BaseShape>Default</t:BaseShape>
</FolderShape>
<m:Restriction>
<t:IsEqualTo>
<t:FieldURI FieldURI="folder:DisplayName"/>
<t:FieldURIOrConstant>
<t:Constant Value="Inbox"/>
</t:FieldURIOrConstant>
</t:IsEqualTo>
</m:Restriction>
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="msgfolderroot"/>
</m:ParentFolderIds>
</FindFolder>
</soap:Body>
</soap:Envelope>
headers:
User-Agent:
- HTTPClient/1.0 (2.8.3, ruby 2.4.4 (2018-03-28))
Accept:
- "*/*"
Date:
- Tue, 04 Sep 2018 05:12:45 GMT
Content-Type:
- text/xml
Cookie:
- ClientId=TMH9PMQHUMIOL0RLW
Authorization:
- Negotiate TlRMTVNTUAADAAAAGAAYAEQAAADGAMYAXAAAAAAAAAAiAQAARABEACIBAAAAAAAAZgEAAAAAAABmAQAABYKJAgAAAACKsgCrRMWhrvDR0QJjG0Dtb4IfWD0Uc2cyO1jML/8FAggCPZ0gmtrTAQEAAAAAAACAxOXpDUTUAW+CH1g9FHNnAAAAAAIAEABFAFgAQwBIAEEATgBHAEUAAQAMAEUAWABGAEUAMAA2AAQAGABFAFgAQwBIAEEATgBHAEUALgBJAE4AVAADACYARQBYAEYARQAwADYALgBFAFgAQwBIAEEATgBHAEUALgBJAE4AVAAFABgARQBYAEMASABBAE4ARwBFAC4ASQBOAFQABwAIACN63+kNRNQBAAAAAAAAAABjAHUAcwB0AG8AbQBlAHIAMwBAAGEANQAzADEAMgA3ADQALgBlAHgAYwBoAGEAbgBnAGUALQBtAGEAaQBsAC4AZQB1AA==
response:
status:
code: 200
message: OK
headers:
Cache-Control:
- private
Transfer-Encoding:
- chunked
Content-Type:
- text/xml; charset=utf-8
Server:
- Microsoft-IIS/8.0
Request-Id:
- 9144d49b-057c-4840-8032-80911701fed9
X-Calculatedbetarget:
- exdag20-2.exchange.int
X-Diaginfo:
- EXDAG20-2
X-Beserver:
- EXDAG20-2
X-Aspnet-Version:
- 4.0.30319
Set-Cookie:
- X-BackEndCookie=S-1-5-21-2149852636-2334046265-983485362-135679=u56Lnp2ejJqBzpnGyczNzMjSy8nOydLLnJzM0seamc/SzMjJxs6bm8eazZnIgYHNz87H0s7P0s/Lq8/Kxc7NxcvK;
expires=Thu, 04-Oct-2018 05:12:45 GMT; path=/EWS; secure; HttpOnly
- exchangecookie=43aef8df84174a8098242a61c783c8ef; expires=Wed, 04-Sep-2019
05:12:45 GMT; path=/; HttpOnly
Persistent-Auth:
- 'true'
X-Powered-By:
- ASP.NET
X-Feserver:
- EXFE06
Date:
- Tue, 04 Sep 2018 05:12:44 GMT
body:
encoding: UTF-8
string: <?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><h:ServerVersionInfo
MajorVersion="15" MinorVersion="0" MajorBuildNumber="1293" MinorBuildNumber="6"
Version="V2_23" xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/></s:Header><s:Body
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><m:FindFolderResponse
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"><m:ResponseMessages><m:FindFolderResponseMessage
ResponseClass="Success"><m:ResponseCode>NoError</m:ResponseCode><m:RootFolder
TotalItemsInView="1" IncludesLastItemInRange="true"><t:Folders><t:Folder><t:FolderId
Id="AQMkADRjMTk4NmJlLTNjMGUtNDk1Yy04MjAxLWE2Nzk0NWYzY2MANTcALgAAA9shP4dg44BKifl+6m/8GgMBALoafj1aZ5lBsuy9VYcX6tAAAAIBDAAAAA=="
ChangeKey="AQAAABYAAAC6Gn49WmeZQbLsvVWHF+rQAAAAABsE"/><t:DisplayName>Inbox</t:DisplayName><t:TotalCount>0</t:TotalCount><t:ChildFolderCount>1</t:ChildFolderCount><t:UnreadCount>0</t:UnreadCount></t:Folder></t:Folders></m:RootFolder></m:FindFolderResponseMessage></m:ResponseMessages></m:FindFolderResponse></s:Body></s:Envelope>
http_version:
recorded_at: Tue, 04 Sep 2018 05:12:45 GMT
recorded_with: VCR 4.0.0

View file

@ -0,0 +1,97 @@
---
http_interactions:
- request:
method: post
uri: https://exchange.example.com/EWS/Exchange.asmx
body:
encoding: UTF-8
string: |
<?xml version="1.0"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages">
<soap:Header>
<t:RequestServerVersion Version="Exchange2010"/>
</soap:Header>
<soap:Body>
<FindFolder xmlns="http://schemas.microsoft.com/exchange/services/2006/messages" Traversal="Shallow">
<FolderShape>
<t:BaseShape>Default</t:BaseShape>
</FolderShape>
<m:Restriction>
<t:IsEqualTo>
<t:FieldURI FieldURI="folder:DisplayName"/>
<t:FieldURIOrConstant>
<t:Constant Value="Inbox"/>
</t:FieldURIOrConstant>
</t:IsEqualTo>
</m:Restriction>
<m:ParentFolderIds>
<t:DistinguishedFolderId Id="msgfolderroot"/>
</m:ParentFolderIds>
</FindFolder>
</soap:Body>
</soap:Envelope>
headers:
User-Agent:
- HTTPClient/1.0 (2.8.3, ruby 2.4.4 (2018-03-28))
Accept:
- "*/*"
Date:
- Tue, 04 Sep 2018 05:29:21 GMT
Content-Type:
- text/xml
Cookie:
- ClientId=E0YFFWDNP0GXXFCYTFUW
Authorization:
- Negotiate TlRMTVNTUAADAAAAGAAYAEQAAADGAMYAXAAAAAAAAAAiAQAARABEACIBAAAAAAAAZgEAAAAAAABmAQAABYKJAgAAAABMEJ04Cv8NvAxULJlH62pCu8GOV5tsEyoaVzgkOoBRqzPDFGW7sfpKAQEAAAAAAACATo87EETUAbvBjlebbBMqAAAAAAIAEABFAFgAQwBIAEEATgBHAEUAAQAMAEUAWABGAEUAMAA2AAQAGABFAFgAQwBIAEEATgBHAEUALgBJAE4AVAADACYARQBYAEYARQAwADYALgBFAFgAQwBIAEEATgBHAEUALgBJAE4AVAAFABgARQBYAEMASABBAE4ARwBFAC4ASQBOAFQABwAIAJ1LzDsQRNQBAAAAAAAAAABjAHUAcwB0AG8AbQBlAHIAMwBAAGEANQAzADEAMgA3ADQALgBlAHgAYwBoAGEAbgBnAGUALQBtAGEAaQBsAC4AZQB1AA==
response:
status:
code: 200
message: OK
headers:
Cache-Control:
- private
Transfer-Encoding:
- chunked
Content-Type:
- text/xml; charset=utf-8
Server:
- Microsoft-IIS/8.0
Request-Id:
- cf74b089-0c14-487e-9f18-15e65ba17d14
X-Calculatedbetarget:
- exdag20-2.exchange.int
X-Diaginfo:
- EXDAG20-2
X-Beserver:
- EXDAG20-2
X-Aspnet-Version:
- 4.0.30319
Set-Cookie:
- X-BackEndCookie=S-1-5-21-2149852636-2334046265-983485362-135679=u56Lnp2ejJqBzpnGyczNzMjSy8nOydLLnJzM0seamc/SzMjJxs6bm8eazZnIgYHNz87H0s7P0s/Lq8/Kxc3Gxc3O;
expires=Thu, 04-Oct-2018 05:29:21 GMT; path=/EWS; secure; HttpOnly
- exchangecookie=36481ec209524d17beb8a645d1e9a389; expires=Wed, 04-Sep-2019
05:29:21 GMT; path=/; HttpOnly
Persistent-Auth:
- 'true'
X-Powered-By:
- ASP.NET
X-Feserver:
- EXFE06
Date:
- Tue, 04 Sep 2018 05:29:21 GMT
body:
encoding: UTF-8
string: <?xml version="1.0" encoding="utf-8"?><s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/"><s:Header><h:ServerVersionInfo
MajorVersion="15" MinorVersion="0" MajorBuildNumber="1293" MinorBuildNumber="6"
Version="V2_23" xmlns:h="http://schemas.microsoft.com/exchange/services/2006/types"
xmlns="http://schemas.microsoft.com/exchange/services/2006/types" xmlns:xsd="http://www.w3.org/2001/XMLSchema"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"/></s:Header><s:Body
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><m:FindFolderResponse
xmlns:m="http://schemas.microsoft.com/exchange/services/2006/messages" xmlns:t="http://schemas.microsoft.com/exchange/services/2006/types"><m:ResponseMessages><m:FindFolderResponseMessage
ResponseClass="Success"><m:ResponseCode>NoError</m:ResponseCode><m:RootFolder
TotalItemsInView="1" IncludesLastItemInRange="true"><t:Folders><t:Folder><t:FolderId
Id="AQMkADRjMTk4NmJlLTNjMGUtNDk1Yy04MjAxLWE2Nzk0NWYzY2MANTcALgAAA9shP4dg44BKifl+6m/8GgMBALoafj1aZ5lBsuy9VYcX6tAAAAIBDAAAAA=="
ChangeKey="AQAAABYAAAC6Gn49WmeZQbLsvVWHF+rQAAAAABsE"/><t:DisplayName>Inbox</t:DisplayName><t:TotalCount>0</t:TotalCount><t:ChildFolderCount>1</t:ChildFolderCount><t:UnreadCount>0</t:UnreadCount></t:Folder></t:Folders></m:RootFolder></m:FindFolderResponseMessage></m:ResponseMessages></m:FindFolderResponse></s:Body></s:Envelope>
http_version:
recorded_at: Tue, 04 Sep 2018 05:29:21 GMT
recorded_with: VCR 4.0.0