ECE366 - Lesson 12
More Testing and Hosting on the Cloud
Instructor: Professor Hong
## WebserviceController.java
```java
package ece366.rpsjdbc.webservice;
import ece366.rpsjdbc.DatabaseConnectionManager;
import ece366.rpsjdbc.Player;
import ece366.rpsjdbc.PlayerDAO;
import org.springframework.web.bind.annotation.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
@CrossOrigin
@RestController
@RequestMapping("/api")
public class WebserviceController {
private final PlayerDAO playerDAO;
private final boolean isTestMode;
// Constructor for dependency injection (used in tests)
public WebserviceController(PlayerDAO playerDAO) {
this.playerDAO = playerDAO;
this.isTestMode = true; // Indicates that this is a test instance
}
// Default constructor (used in production)
public WebserviceController() {
this.isTestMode = false;
this.playerDAO = null; // Will be initialized dynamically in production
}
@GetMapping("/testPlayer")
public String getTestPlayer() {
return "TEST PLAYER";
}
@GetMapping("/player/{id}")
public Player getPlayerById(@PathVariable Long id) {
System.out.println("getPlayerById: " + id);
try {
// Use injected PlayerDAO in test mode, otherwise create it dynamically
PlayerDAO dao = isTestMode ? playerDAO : createPlayerDAO();
Player player = dao.findById(id);
System.out.println(player.toString());
return player;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// Factory method to create PlayerDAO in production
private PlayerDAO createPlayerDAO() throws SQLException {
DatabaseConnectionManager dcm = new DatabaseConnectionManager("db", "rps", "postgres", "password");
Connection connection = dcm.getConnection();
return new PlayerDAO(connection);
}
}
```
## WebserviceControllerTest .java
```java
package ece366.rpsjdbc.webservice;
import static org.junit.jupiter.api.Assertions.*;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.when;
import ece366.rpsjdbc.Player;
import ece366.rpsjdbc.PlayerDAO;
@ExtendWith(MockitoExtension.class)
public class WebserviceControllerTest {
@Mock
private PlayerDAO playerDAO; // Mock the PlayerDAO
private WebserviceController wc; // WebserviceController instance
@BeforeEach
public void setup() {
// Manually inject the mock PlayerDAO into WebserviceController
wc = new WebserviceController(playerDAO);
}
@Test
void getTestPlayer() {
assertEquals("TEST PLAYER", wc.getTestPlayer());
}
@Test
public void getPlayerByIdTest() {
// Create a mock Player object
Player mockPlayer = new Player();
mockPlayer.setPlayerId(1L);
mockPlayer.setUserName("TestUser");
mockPlayer.setTotalWins(600);
// Mock the behavior of PlayerDAO's findById method
when(playerDAO.findById(1L)).thenReturn(mockPlayer);
// Call the method under test
Player p = wc.getPlayerById(1L);
// Verify the result
assertEquals(600, p.getTotalWins());
assertEquals("TestUser", p.getUserName());
assertEquals(1L, p.getPlayerId());
}
}
```
## More Hosting on the Cloud
## docker-compose.yaml
```
services:
db:
image: ece366acr.azurecr.io/rpsdb:latest
build: db
environment:
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=password
ports:
- 5432:5432
restart: always
app:
image: ece366acr.azurecr.io/rpsapp:latest
build: server/rpsjdbc
environment:
- POSTGRES_DB=postgres
- POSTGRES_PASSWORD=password
depends_on:
- db
ports:
- 8080:8080
ui:
image: ece366acr.azurecr.io/rpsui:latest
build: rpsui
depends_on:
- app
ports:
- 80:80
```
## deploy-aci.yaml
```
apiVersion: 2019-12-01
location: eastus
name: rpsContainerGroup
properties:
containers:
- name: db
properties:
image: ece366acr.azurecr.io/rpsdb:latest
environmentVariables:
- name: POSTGRES_USER
value: postgres
- name: POSTGRES_PASSWORD
value: password
resources:
requests:
cpu: 1
memoryInGb: 1.5
ports:
- port: 5432
- name: app
properties:
image: ece366acr.azurecr.io/rpsapp:latest
resources:
requests:
cpu: 1
memoryInGb: 1.5
ports:
- port: 8080
- name: ui
properties:
image: ece366acr.azurecr.io/rpsui:latest
resources:
requests:
cpu: 1
memoryInGb: 1.5
ports:
- port: 80
osType: Linux
ipAddress:
type: Public
dnsNameLabel: moosetracks # Add your desired DNS name label here
ports:
- protocol: tcp
port: 5432
- protocol: tcp
port: 8080
- protocol: tcp
port: 80
imageRegistryCredentials:
- server: ece366acr.azurecr.io
username: 00000000-0000-0000-0000-000000000000
password: your token
tags: {exampleTag: tutorial}
type: Microsoft.ContainerInstance/containerGroups
```
## webservice/Webconfig.java
```java
package ece366.rpsjdbc.webservice;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**") // Apply CORS to all endpoints
.allowedOrigins("http://moosetracks.eastus.azurecontainer.io") // Allow requests from your frontend
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // Allow specific HTTP methods
.allowedHeaders("*") // Allow all headers, including Authorization
.allowCredentials(true); // Allow cookies or Authorization headers
}
}
```
## webservice/WebserviceController.java
```
package ece366.rpsjdbc.webservice;
import ece366.rpsjdbc.DatabaseConnectionManager;
import ece366.rpsjdbc.Player;
import ece366.rpsjdbc.PlayerDAO;
import org.springframework.web.bind.annotation.*;
import java.sql.Connection;
import java.sql.SQLException;
import java.util.List;
import java.util.Map;
@CrossOrigin(origins = {"http://moosetracks.eastus.azurecontainer.io"})
@RestController
@RequestMapping("/api")
public class WebserviceController {
private final PlayerDAO playerDAO;
private final boolean isTestMode;
// Constructor for dependency injection (used in tests)
public WebserviceController(PlayerDAO playerDAO) {
this.playerDAO = playerDAO;
this.isTestMode = true; // Indicates that this is a test instance
}
// Default constructor (used in production)
public WebserviceController() {
this.isTestMode = false;
this.playerDAO = null; // Will be initialized dynamically in production
}
@GetMapping("/testPlayer")
public String getTestPlayer() {
return "TEST PLAYER";
}
@GetMapping("/player/{id}")
public Player getPlayerById(@PathVariable Long id) {
System.out.println("getPlayerById: " + id);
try {
// Use injected PlayerDAO in test mode, otherwise create it dynamically
PlayerDAO dao = isTestMode ? playerDAO : createPlayerDAO();
Player player = dao.findById(id);
System.out.println(player.toString());
return player;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
// Factory method to create PlayerDAO in production
private PlayerDAO createPlayerDAO() throws SQLException {
DatabaseConnectionManager dcm = new DatabaseConnectionManager("localhost", "rps", "postgres", "password");
Connection connection = dcm.getConnection();
return new PlayerDAO(connection);
}
}
```
## Azure Review
```
az login
az acr login --name ece366acr
az acr login --name ece366acr --expose-token
docker compose build
docker compose push
az container create --resource-group ece366rg --file deploy-aci.yaml
```