Skip to content

Commit 4a80b7c

Browse files
committed
add networking stack test
1 parent dd059ff commit 4a80b7c

File tree

4 files changed

+175
-17
lines changed

4 files changed

+175
-17
lines changed

.github/workflows/test.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ jobs:
4242
- name: Build project with error handling
4343
run: |
4444
echo "==== Building Project ===="
45-
if ! go build -o basic-docker main.go image.go; then
45+
if ! go build -o basic-docker main.go network.go image.go; then
4646
echo "Error: Build failed. Please check the errors above." >&2
4747
exit 1
4848
fi

adr-002-networking-stack.md

Lines changed: 109 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -166,6 +166,115 @@ func loadNetworks() {
166166
- `network-attach <network-id> <container-id>`: Attach a container to a network.
167167
- `network-detach <network-id> <container-id>`: Detach a container from a network.
168168

169+
## New Functionality: Ping Between Containers
170+
171+
### Context
172+
To verify connectivity between containers in the same network, a `Ping` function was introduced. This function simulates a ping operation by checking if both containers are attached to the same network and outputs a success message if they are.
173+
174+
### Implementation
175+
The `Ping` function was added to the networking stack with the following signature:
176+
177+
```go
178+
func Ping(networkID, sourceContainerID, targetContainerID string) error {
179+
for _, network := range networks {
180+
if network.ID == networkID {
181+
sourceIP, sourceExists := network.Containers[sourceContainerID]
182+
targetIP, targetExists := network.Containers[targetContainerID]
183+
184+
if !sourceExists || !targetExists {
185+
return errors.New("one or both containers are not in the network")
186+
}
187+
188+
fmt.Printf("Pinging from %s to %s: Success\n", sourceIP, targetIP)
189+
return nil
190+
}
191+
}
192+
return errors.New("network not found")
193+
}
194+
```
195+
196+
### Test Scenario
197+
A test case, `TestPing`, was added to validate this functionality. The test performs the following steps:
198+
1. Creates a network.
199+
2. Attaches two containers to the network.
200+
3. Verifies that the `Ping` function confirms connectivity between the two containers.
201+
202+
#### Test Code
203+
```go
204+
func TestPing(t *testing.T) {
205+
// Setup: Create a network and attach two containers
206+
networkName := "test-network"
207+
CreateNetwork(networkName)
208+
networkID := networks[0].ID
209+
210+
container1 := "container-1"
211+
container2 := "container-2"
212+
213+
err := AttachContainerToNetwork(networkID, container1)
214+
if err != nil {
215+
t.Fatalf("Failed to attach container 1: %v", err)
216+
}
217+
218+
err = AttachContainerToNetwork(networkID, container2)
219+
if err != nil {
220+
t.Fatalf("Failed to attach container 2: %v", err)
221+
}
222+
223+
err = Ping(networkID, container1, container2)
224+
if err != nil {
225+
t.Errorf("Ping failed: %v", err)
226+
}
227+
}
228+
```
229+
230+
### Test Output
231+
232+
The `TestPing` test case was executed successfully, confirming the functionality of the `Ping` feature. Below is the textual output from the test:
233+
234+
```
235+
Network capsule test-network created with ID net-1
236+
Container container-1 attached to network net-1 with IP 192.168.1.2
237+
Container container-2 attached to network net-1 with IP 192.168.1.3
238+
Pinging from 192.168.1.2 to 192.168.1.3: Success
239+
```
240+
241+
This output demonstrates that:
242+
1. A network was created successfully.
243+
2. Containers were attached to the network with unique IP addresses.
244+
3. The `Ping` function verified connectivity between the containers.
245+
246+
## Test Overview
247+
248+
### Purpose
249+
To ensure that containers within the same network can communicate effectively.
250+
251+
### Approach
252+
A basic test was implemented to:
253+
1. Create a network.
254+
2. Attach two containers to the network.
255+
3. Verify connectivity between the containers using a simulated `Ping` function.
256+
257+
### Diagram
258+
```mermaid
259+
graph TD
260+
A[Create Network] --> B[Attach Container 1]
261+
A --> C[Attach Container 2]
262+
B --> D[Ping from Container 1 to Container 2]
263+
C --> D
264+
D --> E[Verify Connectivity]
265+
```
266+
267+
### Consequences
268+
1. **Positive**:
269+
- Provides a simple way to verify container connectivity within a network.
270+
- Enhances the usability of the networking stack.
271+
272+
2. **Negative**:
273+
- Limited to basic connectivity checks; does not simulate real network traffic.
274+
275+
### Status
276+
Implemented and tested.
277+
169278
## Design Diagram
170279
```mermaid
171280
graph TD

main_test.go

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,36 @@ func TestCapsuleManager(t *testing.T) {
142142
}
143143
}
144144

145+
// TestPing verifies that containers in the same network can communicate
146+
func TestPing(t *testing.T) {
147+
// Cleanup: Ensure no existing networks or containers interfere with the test
148+
networks = []Network{}
149+
saveNetworks()
150+
151+
// Setup: Create a network and attach two containers
152+
networkName := "test-network"
153+
CreateNetwork(networkName)
154+
networkID := networks[0].ID
155+
156+
container1 := "container-1"
157+
container2 := "container-2"
158+
159+
err := AttachContainerToNetwork(networkID, container1)
160+
if err != nil {
161+
t.Fatalf("Failed to attach container 1: %v", err)
162+
}
163+
164+
err = AttachContainerToNetwork(networkID, container2)
165+
if err != nil {
166+
t.Fatalf("Failed to attach container 2: %v", err)
167+
}
168+
169+
err = Ping(networkID, container1, container2)
170+
if err != nil {
171+
t.Errorf("Ping failed: %v", err)
172+
}
173+
}
174+
145175
// BenchmarkCapsuleAccess benchmarks the access time for Resource Capsules.
146176
func BenchmarkCapsuleAccess(b *testing.B) {
147177
cm := NewCapsuleManager()

network.go

Lines changed: 35 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -10,10 +10,11 @@ import (
1010

1111
const networksFile = "networks.json"
1212

13+
// Updated Network struct to include IP addresses for containers
1314
type Network struct {
1415
Name string
1516
ID string
16-
Containers []string // List of container IDs attached to this network
17+
Containers map[string]string // Map of container IDs to their IP addresses
1718
}
1819

1920
var networks = []Network{}
@@ -57,7 +58,7 @@ func saveNetworks() {
5758
// CreateNetwork creates a new network capsule
5859
func CreateNetwork(name string) {
5960
id := fmt.Sprintf("net-%d", len(networks)+1)
60-
network := Network{Name: name, ID: id, Containers: []string{}}
61+
network := Network{Name: name, ID: id, Containers: make(map[string]string)}
6162
networks = append(networks, network)
6263

6364
// Register the network as a resource capsule
@@ -87,19 +88,20 @@ func DeleteNetwork(id string) {
8788
fmt.Printf("Network with ID %s not found\n", id)
8889
}
8990

90-
// AttachContainerToNetwork attaches a container to a network capsule
91+
// Updated AttachContainerToNetwork to assign IP addresses
9192
func AttachContainerToNetwork(networkID, containerID string) error {
9293
for i, network := range networks {
9394
if network.ID == networkID {
9495
// Check if the container is already attached
95-
for _, c := range network.Containers {
96-
if c == containerID {
97-
return errors.New("container is already attached to the network")
98-
}
96+
if _, exists := network.Containers[containerID]; exists {
97+
return errors.New("container is already attached to the network")
9998
}
100-
// Attach the container
101-
networks[i].Containers = append(network.Containers, containerID)
102-
fmt.Printf("Container %s attached to network %s\n", containerID, networkID)
99+
100+
// Assign an IP address to the container
101+
ipAddress := fmt.Sprintf("192.168.%d.%d", i+1, len(network.Containers)+2)
102+
networks[i].Containers[containerID] = ipAddress
103+
saveNetworks()
104+
fmt.Printf("Container %s attached to network %s with IP %s\n", containerID, networkID, ipAddress)
103105
return nil
104106
}
105107
}
@@ -111,19 +113,36 @@ func DetachContainerFromNetwork(networkID, containerID string) error {
111113
for i, network := range networks {
112114
if network.ID == networkID {
113115
// Find and remove the container
114-
for j, c := range network.Containers {
115-
if c == containerID {
116-
networks[i].Containers = append(network.Containers[:j], network.Containers[j+1:]...)
117-
fmt.Printf("Container %s detached from network %s\n", containerID, networkID)
118-
return nil
119-
}
116+
if _, exists := network.Containers[containerID]; exists {
117+
delete(networks[i].Containers, containerID)
118+
saveNetworks()
119+
fmt.Printf("Container %s detached from network %s\n", containerID, networkID)
120+
return nil
120121
}
121122
return errors.New("container not found in the network")
122123
}
123124
}
124125
return errors.New("network not found")
125126
}
126127

128+
// New Ping function to test connectivity between containers
129+
func Ping(networkID, sourceContainerID, targetContainerID string) error {
130+
for _, network := range networks {
131+
if network.ID == networkID {
132+
sourceIP, sourceExists := network.Containers[sourceContainerID]
133+
targetIP, targetExists := network.Containers[targetContainerID]
134+
135+
if !sourceExists || !targetExists {
136+
return errors.New("one or both containers are not in the network")
137+
}
138+
139+
fmt.Printf("Pinging from %s to %s: Success\n", sourceIP, targetIP)
140+
return nil
141+
}
142+
}
143+
return errors.New("network not found")
144+
}
145+
127146
// Call loadNetworks during initialization
128147
func init() {
129148
loadNetworks()

0 commit comments

Comments
 (0)