Coverage Report

Created: 2026-03-25 23:22

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/home/runner/work/tenet/tenet/tenet-aws/src/models/mod.rs
Line
Count
Source
1
//! Shared models for tenet AWS services
2
//!
3
//! This module contains the data models used across tenet services:
4
//! - Component (unified model for C4 containers and components)
5
//! - Organisation and related request types
6
//! - Rule and related request types
7
//! - Member and role types for organisation membership
8
//! - Invitation types for inviting users to organisations
9
//! - User profile for active organisation tracking
10
//! - View types for simplified API responses
11
//! - Connection types for relationships between components
12
13
pub mod actor;
14
pub mod component;
15
pub mod connection;
16
pub mod external_system;
17
pub mod graph;
18
pub mod graph_layout;
19
pub mod id;
20
pub mod invitation;
21
pub mod member;
22
pub mod organisation;
23
pub mod profile;
24
pub mod project;
25
pub mod quality_attribute;
26
pub mod quality_component_link;
27
pub mod role;
28
pub mod rule;
29
pub mod skill;
30
pub mod spec;
31
pub mod store;
32
pub mod unified_component;
33
pub mod unified_graph_codec;
34
pub mod unified_graph_edge_codec;
35
pub mod unified_graph_node_codec;
36
37
use serde::{Deserialize, Serialize};
38
39
use crate::models::{component::Component, project::Project, rule::Rule};
40
41
/// C4 project structure with containers and components for config response.
42
#[derive(Debug, Clone, Serialize, Deserialize)]
43
pub struct ProjectArchitectureConfig {
44
    #[serde(flatten)]
45
    pub project: Project,
46
    pub containers: Vec<ContainerConfig>,
47
}
48
49
/// C4 container with its direct child components for config response.
50
#[derive(Debug, Clone, Serialize, Deserialize)]
51
pub struct ContainerConfig {
52
    #[serde(flatten)]
53
    pub container: Component,
54
    pub components: Vec<Component>,
55
}
56
57
impl ContainerConfig {
58
20
    pub fn new(container: Component, components: Vec<Component>) -> Self {
59
20
        Self {
60
20
            container,
61
20
            components,
62
20
        }
63
20
    }
64
}
65
66
/// Full account configuration returned to MCP servers
67
#[derive(Debug, Clone, Serialize, Deserialize)]
68
pub struct TenetAccount {
69
    /// Organisation-level rules
70
    pub rules: Vec<Rule>,
71
    /// Projects with their C4 hierarchy
72
    pub projects: Vec<ProjectArchitectureConfig>,
73
}
74
75
// =============================================================================
76
// Tests
77
// =============================================================================
78
79
#[cfg(test)]
80
mod tests {
81
    use crate::models::{
82
        component::{
83
            ArchitectureComponentKind, ArchitectureComponentMetadata, Component, ContainerKind,
84
            ContainerMetadata,
85
        },
86
        role::Role,
87
    };
88
89
    use super::*;
90
    use crate::test_support::must_ok;
91
92
    #[allure_rs::allure_parent_suite("tenet-aws")]
93
    #[allure_rs::allure_test]
94
    #[test]
95
    fn test_role_is_admin() {
96
        assert!(Role::Admin.is_admin());
97
        assert!(!Role::User.is_admin());
98
    }
99
100
    #[allure_rs::allure_parent_suite("tenet-aws")]
101
    #[allure_rs::allure_test]
102
    #[test]
103
    fn test_role_from_str() {
104
        assert_eq!(must_ok("admin".parse::<Role>()), Role::Admin);
105
        assert_eq!(must_ok("user".parse::<Role>()), Role::User);
106
        assert_eq!(must_ok("ADMIN".parse::<Role>()), Role::Admin);
107
        assert!("invalid".parse::<Role>().is_err());
108
    }
109
110
    #[allure_rs::allure_parent_suite("tenet-aws")]
111
    #[allure_rs::allure_test]
112
    #[test]
113
    fn test_role_display() {
114
        assert_eq!(Role::Admin.to_string(), "admin");
115
        assert_eq!(Role::User.to_string(), "user");
116
    }
117
118
    #[allure_rs::allure_parent_suite("tenet-aws")]
119
    #[allure_rs::allure_test]
120
    #[test]
121
    fn test_container_config_new() {
122
        let project_id: crate::models::project::ProjectId = must_ok(
123
            "550e8400-e29b-41d4-a716-446655440002"
124
                .to_string()
125
                .try_into(),
126
        );
127
        let organisation_id: crate::models::organisation::OrganisationId = must_ok(
128
            "550e8400-e29b-41d4-a716-446655440000"
129
                .to_string()
130
                .try_into(),
131
        );
132
133
        let app = must_ok(Component::new_container(
134
            project_id.clone(),
135
            organisation_id.clone(),
136
            "Web Frontend".to_string(),
137
            Some("React app".to_string()),
138
            "apps/web/**".to_string(),
139
            &ContainerMetadata {
140
                container_kind: ContainerKind::App,
141
                technology: Some("TypeScript".to_string()),
142
                framework: Some("React".to_string()),
143
                runtime: None,
144
                deployment: None,
145
            },
146
        ));
147
148
        let module = must_ok(Component::new_architecture_component(
149
            app.id.clone(),
150
            project_id.clone(),
151
            organisation_id,
152
            "Auth Module".to_string(),
153
            None,
154
            "apps/web/src/auth/**".to_string(),
155
            &ArchitectureComponentMetadata {
156
                component_kind: ArchitectureComponentKind::Module,
157
            },
158
        ));
159
160
        let config = ContainerConfig::new(app, vec![module]);
161
        assert_eq!(config.components.len(), 1);
162
    }
163
}