189 lines
7.3 KiB
C++
189 lines
7.3 KiB
C++
/*
|
|
* This file is open source software, licensed to you under the terms
|
|
* of the Apache License, Version 2.0 (the "License"). See the NOTICE file
|
|
* distributed with this work for additional information regarding copyright
|
|
* ownership. You may not use this file except in compliance with the License.
|
|
*
|
|
* You may obtain a copy of the License at
|
|
*
|
|
* http://www.apache.org/licenses/LICENSE-2.0
|
|
*
|
|
* Unless required by applicable law or agreed to in writing,
|
|
* software distributed under the License is distributed on an
|
|
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
|
* KIND, either express or implied. See the License for the
|
|
* specific language governing permissions and limitations
|
|
* under the License.
|
|
*/
|
|
/*
|
|
* Copyright (C) 2015 Cloudius Systems, Ltd.
|
|
*/
|
|
|
|
#include <algorithm>
|
|
#include <iostream>
|
|
#include "core/reactor.hh"
|
|
#include "core/fstream.hh"
|
|
#include "core/shared_ptr.hh"
|
|
#include "core/app-template.hh"
|
|
#include "core/do_with.hh"
|
|
#include "core/seastar.hh"
|
|
#include "test-utils.hh"
|
|
|
|
struct writer {
|
|
output_stream<char> out;
|
|
writer(file f) : out(make_file_output_stream(
|
|
make_lw_shared<file>(std::move(f)))) {}
|
|
};
|
|
|
|
struct reader {
|
|
input_stream<char> in;
|
|
reader(file f) : in(make_file_input_stream(
|
|
make_lw_shared<file>(std::move(f)))) {}
|
|
};
|
|
|
|
SEASTAR_TEST_CASE(test_fstream) {
|
|
auto sem = make_lw_shared<semaphore>(0);
|
|
|
|
engine().open_file_dma("testfile.tmp",
|
|
open_flags::rw | open_flags::create | open_flags::truncate).then([sem] (file f) {
|
|
auto w = make_shared<writer>(std::move(f));
|
|
auto buf = static_cast<char*>(::malloc(4096));
|
|
memset(buf, 0, 4096);
|
|
buf[0] = '[';
|
|
buf[1] = 'A';
|
|
buf[4095] = ']';
|
|
w->out.write(buf, 4096).then([buf, w] {
|
|
::free(buf);
|
|
return make_ready_future<>();
|
|
}).then([w] {
|
|
auto buf = static_cast<char*>(::malloc(8192));
|
|
memset(buf, 0, 8192);
|
|
buf[0] = '[';
|
|
buf[1] = 'B';
|
|
buf[8191] = ']';
|
|
return w->out.write(buf, 8192).then([buf, w] {
|
|
::free(buf);
|
|
return w->out.close().then([w] {});
|
|
});
|
|
}).then([] {
|
|
return engine().open_file_dma("testfile.tmp", open_flags::ro);
|
|
}).then([] (file f) {
|
|
/* file content after running the above:
|
|
* 00000000 5b 41 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |[A..............|
|
|
* 00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
|
* *
|
|
* 00000ff0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5d |...............]|
|
|
* 00001000 5b 42 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |[B..............|
|
|
* 00001010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
|
|
* *
|
|
* 00002ff0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 5d |...............]|
|
|
* 00003000
|
|
*/
|
|
auto r = make_shared<reader>(std::move(f));
|
|
return r->in.read_exactly(4096 + 8192).then([r] (temporary_buffer<char> buf) {
|
|
auto p = buf.get();
|
|
BOOST_REQUIRE(p[0] == '[' && p[1] == 'A' && p[4095] == ']');
|
|
BOOST_REQUIRE(p[4096] == '[' && p[4096 + 1] == 'B' && p[4096 + 8191] == ']');
|
|
return make_ready_future<>();
|
|
});
|
|
}).finally([sem] () {
|
|
sem->signal();
|
|
});
|
|
});
|
|
|
|
return sem->wait();
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_fstream_unaligned) {
|
|
auto sem = make_lw_shared<semaphore>(0);
|
|
|
|
engine().open_file_dma("testfile.tmp",
|
|
open_flags::rw | open_flags::create | open_flags::truncate).then([sem] (file f) {
|
|
auto w = make_shared<writer>(std::move(f));
|
|
auto buf = static_cast<char*>(::malloc(40));
|
|
memset(buf, 0, 40);
|
|
buf[0] = '[';
|
|
buf[1] = 'A';
|
|
buf[39] = ']';
|
|
w->out.write(buf, 40).then([buf, w] {
|
|
::free(buf);
|
|
return w->out.close().then([w] {});
|
|
}).then([] {
|
|
return engine().open_file_dma("testfile.tmp", open_flags::ro);
|
|
}).then([] (file f) {
|
|
return do_with(std::move(f), [] (file& f) {
|
|
return f.size().then([] (size_t size) {
|
|
// assert that file was indeed truncated to the amount of bytes written.
|
|
BOOST_REQUIRE(size == 40);
|
|
return make_ready_future<>();
|
|
});
|
|
});
|
|
}).then([] {
|
|
return engine().open_file_dma("testfile.tmp", open_flags::ro);
|
|
}).then([] (file f) {
|
|
auto r = make_shared<reader>(std::move(f));
|
|
return r->in.read_exactly(40).then([r] (temporary_buffer<char> buf) {
|
|
auto p = buf.get();
|
|
BOOST_REQUIRE(p[0] == '[' && p[1] == 'A' && p[39] == ']');
|
|
return make_ready_future<>();
|
|
});
|
|
}).finally([sem] () {
|
|
sem->signal();
|
|
});
|
|
});
|
|
|
|
return sem->wait();
|
|
}
|
|
|
|
future<> test_consume_until_end(uint64_t size) {
|
|
return open_file_dma("testfile.tmp",
|
|
open_flags::rw | open_flags::create | open_flags::truncate).then([size] (file f) {
|
|
return do_with(make_lw_shared(std::move(f)), [size] (lw_shared_ptr<file> f) {
|
|
return do_with(make_file_output_stream(f), [size] (output_stream<char>& out) {
|
|
std::vector<char> buf(size);
|
|
std::iota(buf.begin(), buf.end(), 0);
|
|
return out.write(buf.data(), buf.size()).then([&out] {
|
|
return out.flush();
|
|
});
|
|
}).then([f] {
|
|
return f->size();
|
|
}).then([size, f] (size_t real_size) {
|
|
BOOST_REQUIRE_EQUAL(size, real_size);
|
|
}).then([size, f] {
|
|
auto consumer = [offset = uint64_t(0), size] (temporary_buffer<char> buf) mutable -> future<input_stream<char>::unconsumed_remainder> {
|
|
if (!buf) {
|
|
return make_ready_future<input_stream<char>::unconsumed_remainder>(temporary_buffer<char>());
|
|
}
|
|
BOOST_REQUIRE(offset + buf.size() <= size);
|
|
std::vector<char> expected(buf.size());
|
|
std::iota(expected.begin(), expected.end(), offset);
|
|
offset += buf.size();
|
|
BOOST_REQUIRE(std::equal(buf.begin(), buf.end(), expected.begin()));
|
|
return make_ready_future<input_stream<char>::unconsumed_remainder>(std::experimental::nullopt);
|
|
};
|
|
return do_with(make_file_input_stream(f), std::move(consumer), [size] (input_stream<char>& in, auto& consumer) {
|
|
return in.consume(consumer);
|
|
});
|
|
});
|
|
});
|
|
});
|
|
}
|
|
|
|
|
|
SEASTAR_TEST_CASE(test_consume_aligned_file) {
|
|
return test_consume_until_end(4096);
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_consume_empty_file) {
|
|
return test_consume_until_end(0);
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_consume_unaligned_file) {
|
|
return test_consume_until_end(1);
|
|
}
|
|
|
|
SEASTAR_TEST_CASE(test_consume_unaligned_file_large) {
|
|
return test_consume_until_end((1 << 20) + 1);
|
|
}
|
|
|