diff --git a/src/erlazure.app.src b/src/erlazure.app.src index 4e35418..0da7949 100644 --- a/src/erlazure.app.src +++ b/src/erlazure.app.src @@ -1,6 +1,6 @@ {application, erlazure, [{description, "Windows Azure Erlang bindings"}, - {vsn, "0.3.0.1"}, + {vsn, "0.3.0.2"}, {modules, []}, {registered, []}, {applications, [kernel, stdlib, crypto, inets, ssl]}, diff --git a/src/erlazure.erl b/src/erlazure.erl index d1a6855..55857f8 100644 --- a/src/erlazure.erl +++ b/src/erlazure.erl @@ -678,12 +678,13 @@ handle_call({put_block, Container, Blob, BlockId, Content, Options}, _From, Stat return_response(Code, Body, State, ?http_created, created); % Put block list -handle_call({put_block_list, Container, Blob, BlockRefs, Options}, _From, State) -> +handle_call({put_block_list, Container, Blob, BlockRefs, Options0}, _From, State) -> ServiceContext = new_service_context(?blob_service, State), + {ExtraReqOpts, Options} = proplist_take(req_opts, Options0, []), ReqOptions = [{method, put}, {path, lists:concat([Container, "/", Blob])}, {body, erlazure_blob:get_request_body(BlockRefs)}, - {params, [{comp, "blocklist"}] ++ Options}], + {params, [{comp, "blocklist"}] ++ Options} | ExtraReqOpts], ReqContext = new_req_context(?blob_service, ReqOptions, State), {Code, Body} = execute_request(ServiceContext, ReqContext), @@ -1085,6 +1086,14 @@ ensure_wrapped_key(#{key := Key} = InitOpts) -> InitOpts#{key := wrap(Key)} end. +proplist_take(Key, Proplist, Default) -> + case lists:keytake(Key, 1, Proplist) of + false -> + {Default, Proplist}; + {value, {Key, Value}, NewProplist} -> + {Value, NewProplist} + end. + %%==================================================================== %% Tests %%==================================================================== diff --git a/test/erlazure_SUITE.erl b/test/erlazure_SUITE.erl index 9c4707d..604fba3 100644 --- a/test/erlazure_SUITE.erl +++ b/test/erlazure_SUITE.erl @@ -175,10 +175,10 @@ t_put_block(Config) -> Container = container_name(?FUNCTION_NAME), ?assertMatch({[], _}, erlazure:list_containers(Pid)), ?assertMatch({ok, created}, erlazure:create_container(Pid, Container)), - %% Upload some blocks - Opts = [{content_type, "text/csv"}], + %% Upload some blocks. Note: this content-type will be overwritten later by `put_block_list'. + Opts1 = [{content_type, "application/json"}], BlobName = "blob1", - ?assertMatch({ok, created}, erlazure:put_block_blob(Pid, Container, BlobName, <<>>, Opts)), + ?assertMatch({ok, created}, erlazure:put_block_blob(Pid, Container, BlobName, <<"0">>, Opts1)), %% Note: this short name is important for this test. It'll produce a base64 string %% that's padded. That padding must be URL-encoded when sending the request, but not %% when generating the string to sign. @@ -187,21 +187,29 @@ t_put_block(Config) -> %% Testing iolists BlockId2 = <<"blo2">>, ?assertMatch({ok, created}, erlazure:put_block(Pid, Container, BlobName, BlockId2, [<<"\n">>, ["b", [$\n]]])), - %% Not yet committed. - ?assertMatch({ok, <<"">>}, erlazure:get_blob(Pid, Container, BlobName)), + %% Not yet committed. Contains only the data from the blob creation. + ?assertMatch({ok, <<"0">>}, erlazure:get_blob(Pid, Container, BlobName)), %% Committing BlockList1 = [{BlockId1, latest}], ?assertMatch({ok, created}, erlazure:put_block_list(Pid, Container, BlobName, BlockList1)), - %% Committed only first block. + %% Committed only first block. Initial data was lost, as it was not in the block list. ?assertMatch({ok, <<"a">>}, erlazure:get_blob(Pid, Container, BlobName)), %% Block 2 was dropped after committing. ?assertMatch({[#blob_block{id = "blo1"}], _}, erlazure:get_block_list(Pid, Container, BlobName)), BlockId3 = <<"blo3">>, ?assertMatch({ok, created}, erlazure:put_block(Pid, Container, BlobName, BlockId3, [<<"\n">>, ["b", [$\n]]])), %% Commit both blocks + Opts2 = [{req_opts, [{headers, [{"x-ms-blob-content-type", "text/csv"}]}]}], BlockList2 = [{BlockId1, committed}, {BlockId3, uncommitted}], - ?assertMatch({ok, created}, erlazure:put_block_list(Pid, Container, BlobName, BlockList2)), + ?assertMatch({ok, created}, erlazure:put_block_list(Pid, Container, BlobName, BlockList2, Opts2)), ?assertMatch({ok, <<"a\nb\n">>}, erlazure:get_blob(Pid, Container, BlobName)), + %% Check content type. + ListedBlobs = erlazure:list_blobs(Pid, Container), + ?assertMatch({[#cloud_blob{name = "blob1"}], _}, + ListedBlobs), + {[#cloud_blob{name = "blob1", properties = Props}], _} = ListedBlobs, + %% Content-type from `put_block_list' prevails. + ?assertMatch(#{content_type := "text/csv"}, maps:from_list(Props)), %% Delete container ?assertMatch({ok, deleted}, erlazure:delete_container(Pid, Container)), ok.