Add OSDK demos in Asterinas Book in OSDK integration test

This commit is contained in:
Jianfeng Jiang
2024-03-14 09:17:49 +00:00
committed by Tate, Hongliang Tian
parent 11ff0521e7
commit 63499c675c
15 changed files with 240 additions and 35 deletions

View File

@ -32,8 +32,9 @@ jobs:
id: unit_test id: unit_test
run: cd osdk && cargo build && RUSTUP_HOME=/root/.rustup cargo test run: cd osdk && cargo build && RUSTUP_HOME=/root/.rustup cargo test
# Test OSDK in the same environment as described in the OSDK User Guide in the Asterinas Book. # Test OSDK in the same environment
osdk_doc_env_test: # as described in the OSDK User Guide in the Asterinas Book.
osdk-doc-env-test:
runs-on: ubuntu-latest runs-on: ubuntu-latest
timeout-minutes: 15 timeout-minutes: 15
container: asterinas/osdk:0.4.0 container: asterinas/osdk:0.4.0
@ -44,6 +45,10 @@ jobs:
- name: Unit test - name: Unit test
id: unit_test id: unit_test
# Github's actions/checkout@v4 will result in a new user (not root)
# and thus not using the Rust environment we set up in the container.
# So the RUSTUP_HOME needs to be set here.
# This only breaks when we invoke Cargo in the integration test of OSDK
# since the OSDK toolchain is not nightly.
run: cd osdk && cargo build && RUSTUP_HOME=/root/.rustup cargo test run: cd osdk && cargo build && RUSTUP_HOME=/root/.rustup cargo test
# TODO: test the demos in Asterinas Book

View File

@ -185,4 +185,5 @@ check: $(CARGO_OSDK)
clean: clean:
@cargo clean @cargo clean
@cd docs && mdbook clean @cd docs && mdbook clean
@make --no-print-directory -C regression clean @make --no-print-directory -C regression clean
@rm -f $(CARGO_OSDK)

View File

@ -17,11 +17,7 @@ touch Cargo.toml
Then, add the following content to `Cargo.toml`: Then, add the following content to `Cargo.toml`:
```toml {{#include ../../../../osdk/tests/examples_in_book/work_in_workspace_templates/Cargo.toml}}
[workspace]
members = []
resolver = "2"
```
## Creating a kernel project and a library project ## Creating a kernel project and a library project
@ -60,31 +56,17 @@ Next, add the following function to `mymodule/src/lib.rs`.
This function will calculate the available memory This function will calculate the available memory
after booting: after booting:
```rust {{#include ../../../../osdk/tests/examples_in_book/work_in_workspace_templates/mymodule/src/lib.rs}}
pub fn available_memory() -> usize {
let regions = aster_frame::boot::memory_regions();
regions.iter().map(|region| region.len()).sum()
}
```
Then, add a dependency on `mymodule` to `myos/Cargo.toml`: Then, add a dependency on `mymodule` to `myos/Cargo.toml`:
```toml {{#include ../../../../osdk/tests/examples_in_book/work_in_workspace_templates/myos/Cargo.toml}}
[dependencies]
mymodule = { path = "../mymodule" }
```
In `myos/src/lib.rs`, In `myos/src/lib.rs`,
modify the main function as follows. modify the file content as follows.
This function will call the function from `mymodule`: This main function will call the function from `mymodule`:
```rust {{#include ../../../../osdk/tests/examples_in_book/work_in_workspace_templates/myos/src/lib.rs}}
#[aster_main]
fn kernel_main() {
let avail_mem_as_mb = mymodule::available_memory() / 1_000_000;
println!("The available memory is {} MB", avail_mem_as_mb);
}
```
## Building and Running the kernel ## Building and Running the kernel

2
osdk/Cargo.lock generated
View File

@ -128,7 +128,7 @@ dependencies = [
[[package]] [[package]]
name = "cargo-osdk" name = "cargo-osdk"
version = "0.4.0" version = "0.4.1"
dependencies = [ dependencies = [
"assert_cmd", "assert_cmd",
"clap", "clap",

View File

@ -81,12 +81,12 @@ pub struct CrateInfo {
pub path: String, pub path: String,
} }
/// Retrieve the default member in the workspace. /// Retrieve the default member in the workspace.
/// ///
/// If there is only one kernel crate, return that crate; /// If there is only one kernel crate, return that crate;
/// If there are multiple kernel crates or no kernel crates in the workspace, /// If there are multiple kernel crates or no kernel crates in the workspace,
/// this function will exit with an error. /// this function will exit with an error.
/// ///
/// A crate is considered a kernel crate if it utilizes the `aster_main` macro. /// A crate is considered a kernel crate if it utilizes the `aster_main` macro.
fn get_default_member(metadata: &serde_json::Value) -> &str { fn get_default_member(metadata: &serde_json::Value) -> &str {
let default_members = metadata let default_members = metadata

View File

@ -6,5 +6,6 @@
mod cli; mod cli;
mod commands; mod commands;
mod examples_in_book;
mod integration; mod integration;
mod util; mod util;

View File

@ -0,0 +1,46 @@
// SPDX-License-Identifier: MPL-2.0
use std::{fs, path::PathBuf};
use crate::util::cargo_osdk;
#[test]
fn create_a_kernel_project() {
let workdir = "/tmp";
let kernel = "my_foo_os";
let kernel_path = PathBuf::from(workdir).join(kernel);
if kernel_path.exists() {
fs::remove_dir_all(&kernel_path).unwrap();
}
cargo_osdk(&["new", "--kernel", kernel])
.current_dir(workdir)
.unwrap();
assert!(kernel_path.is_dir());
assert!(kernel_path.join("Cargo.toml").is_file());
assert!(kernel_path.join("rust-toolchain.toml").is_file());
fs::remove_dir_all(&kernel_path).unwrap();
}
#[test]
fn create_a_library_project() {
let workdir = "/tmp";
let module = "my_foo_module";
let module_path = PathBuf::from(workdir).join(module);
if module_path.exists() {
fs::remove_dir_all(&module_path).unwrap();
}
cargo_osdk(&["new", module]).current_dir(workdir).unwrap();
assert!(module_path.is_dir());
assert!(module_path.join("Cargo.toml").is_file());
assert!(module_path.join("rust-toolchain.toml").is_file());
fs::remove_dir_all(&module_path).unwrap();
}

View File

@ -0,0 +1,7 @@
// SPDX-License-Identifier: MPL-2.0
//! This module contains the demos in OSDK section in the Asterinas Book.
mod create_os_projects;
mod test_and_run_projects;
mod work_in_workspace;

View File

@ -0,0 +1,56 @@
// SPDX-License-Identifier: MPL-2.0
use std::{fs, path::PathBuf};
use crate::util::cargo_osdk;
#[test]
fn create_and_run_kernel() {
let work_dir = "/tmp";
let os_name = "myos";
let os_dir = PathBuf::from(work_dir).join(os_name);
if os_dir.exists() {
fs::remove_dir_all(&os_dir).unwrap();
}
let mut command = cargo_osdk(&["new", "--kernel", os_name]);
command.current_dir(work_dir);
command.ok().unwrap();
let mut command = cargo_osdk(&["build"]);
command.current_dir(&os_dir);
command.ok().unwrap();
let mut command = cargo_osdk(&["run"]);
command.current_dir(&os_dir);
let output = command.output().unwrap();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
assert!(stdout.contains("Hello world from guest kernel!"));
fs::remove_dir_all(&os_dir).unwrap();
}
#[test]
fn create_and_test_library() {
let work_dir = "/tmp";
let module_name = "mymodule";
let module_dir = PathBuf::from(work_dir).join(module_name);
if module_dir.exists() {
fs::remove_dir_all(&module_dir).unwrap();
}
let mut command = cargo_osdk(&["new", module_name]);
command.current_dir(work_dir);
command.ok().unwrap();
let mut command = cargo_osdk(&["test"]);
command.current_dir(&module_dir);
command.output().unwrap();
fs::remove_dir_all(&module_dir).unwrap();
}

View File

@ -0,0 +1,75 @@
// SPDX-License-Identifier: MPL-2.0
use std::{
env,
fs::{self, OpenOptions},
io::Write,
path::PathBuf,
};
use crate::util::cargo_osdk;
#[test]
fn work_in_workspace() {
let workdir = "/tmp";
let workspace_name = "myworkspace";
// Create workspace and its manifest
let workspace_dir = PathBuf::from(workdir).join(workspace_name);
if workspace_dir.is_dir() {
fs::remove_dir_all(&workspace_dir).unwrap();
}
fs::create_dir_all(&workspace_dir).unwrap();
env::set_current_dir(&workspace_dir).unwrap();
let workspace_toml = include_str!("work_in_workspace_templates/Cargo.toml");
fs::write(workspace_dir.join("Cargo.toml"), workspace_toml).unwrap();
// Create a kernel project and a library project
let kernel = "myos";
let module = "mymodule";
cargo_osdk(&["new", "--kernel", kernel]).ok().unwrap();
cargo_osdk(&["new", module]).ok().unwrap();
// Add a test function to mymodule/src/lib.rs
let module_src_path = workspace_dir.join(module).join("src").join("lib.rs");
assert!(module_src_path.is_file());
let mut module_src_file = OpenOptions::new()
.append(true)
.open(&module_src_path)
.unwrap();
module_src_file
.write_all(include_bytes!("work_in_workspace_templates/mymodule/src/lib.rs"))
.unwrap();
module_src_file.flush().unwrap();
// Add dependency to myos/Cargo.toml
let kernel_manifest_path = workspace_dir.join(kernel).join("Cargo.toml");
assert!(kernel_manifest_path.is_file());
let mut kernel_manifest_file = OpenOptions::new()
.append(true)
.open(&kernel_manifest_path)
.unwrap();
kernel_manifest_file
.write_all(include_bytes!("work_in_workspace_templates/myos/Cargo.toml"))
.unwrap();
kernel_manifest_file.flush().unwrap();
// Add the content to myos/src/lib.rs
let kernel_src_path = workspace_dir.join(kernel).join("src").join("lib.rs");
assert!(kernel_src_path.is_file());
fs::write(&kernel_src_path, include_str!("work_in_workspace_templates/myos/src/lib.rs")).unwrap();
// Run subcommand build & run
cargo_osdk(&["build"]).ok().unwrap();
let output = cargo_osdk(&["run"]).output().unwrap();
let stdout = String::from_utf8_lossy(&output.stdout).to_string();
assert!(stdout.contains("The available memory is"));
// Run subcommand test
cargo_osdk(&["test"]).output().unwrap();
// Remove the directory
fs::remove_dir_all(&workspace_dir).unwrap();
}

View File

@ -0,0 +1,3 @@
[workspace]
members = []
resolver = "2"

View File

@ -0,0 +1,6 @@
// SPDX-License-Identifier: MPL-2.0
pub fn available_memory() -> usize {
let regions = aster_frame::boot::memory_regions();
regions.iter().map(|region| region.len()).sum()
}

View File

@ -0,0 +1,2 @@
[dependencies]
mymodule = { path = "../mymodule" }

View File

@ -0,0 +1,12 @@
// SPDX-License-Identifier: MPL-2.0
#![no_std]
#![forbid(unsafe_code)]
use aster_frame::prelude::*;
#[aster_main]
fn kernel_main() {
let avail_mem_as_mb = mymodule::available_memory() / 1_000_000;
println!("The available memory is {} MB", avail_mem_as_mb);
}

View File

@ -3,6 +3,15 @@
# This image is for the OSDK GitHub CI. # This image is for the OSDK GitHub CI.
# The environment is consistent with the one # The environment is consistent with the one
# described in the OSDK User Guide section of the Asterinas Book. # described in the OSDK User Guide section of the Asterinas Book.
#
# TODO: We should build the Asterinas image based on the OSDK image
# since Asterinas is managed by OSDK itself.
# However, currently, these two images have different contents.
# The main distinction is that
# QEMU, grub, and OVMF in the OSDK image are installed via apt,
# while these tools in the Asterinas image are built from source.
# Some boot methods in Asterinas only function properly
# when using the tools that are built from source.
FROM ubuntu:22.04 FROM ubuntu:22.04