.vscode
.factorypath
+
+coverage.*
#
# ============LICENSE_START=======================================================
-# ONAP : ccsdk oran
+# O-RAN-SC
# ================================================================================
-# Copyright (C) 2019-2020 Nordix Foundation. All rights reserved.
+# Copyright (C) 2021 Nordix Foundation. All rights reserved.
# ================================================================================
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
RUN chmod -R 777 /opt/app/dmaap-adaptor-service/config/
ADD target/${JAR} /opt/app/dmaap-adaptor-service/dmaap-adaptor.jar
-CMD ["java", "-jar", "/opt/app/policy-agent/dmaap-adaptor.jar"]
+CMD ["java", "-jar", "/opt/app/dmaap-adaptor-service/dmaap-adaptor.jar"]
import static org.assertj.core.api.Assertions.assertThat;
import static org.awaitility.Awaitility.await;
-import com.google.gson.Gson;
-import com.google.gson.GsonBuilder;
import com.google.gson.JsonParser;
import java.io.FileOutputStream;
import org.oran.dmaapadapter.repository.InfoTypes;
import org.oran.dmaapadapter.repository.Jobs;
import org.oran.dmaapadapter.tasks.ProducerRegstrationTask;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
"app.configuration-filepath=./src/test/resources/test_application_configuration.json"//
})
class ApplicationTest {
- private static final Logger logger = LoggerFactory.getLogger(ApplicationTest.class);
@Autowired
private ApplicationConfig applicationConfig;
@LocalServerPort
int localServerHttpPort;
- private static Gson gson = new GsonBuilder().create();
-
static class TestApplicationConfig extends ApplicationConfig {
@Override
public String getEcsBaseUrl() {
return ErrorResponse.create("", HttpStatus.NOT_FOUND);
} else {
String resp = dmaapResponses.remove(0);
+ logger.info("DMAAP simulator returned: {}", resp);
return new ResponseEntity<>(resp, HttpStatus.OK);
}
ProducerJobInfo request =
new ProducerJobInfo(job.jobDefinition, "ID", job.infoTypeId, job.jobResultUri, job.owner, "TIMESTAMP");
String body = gson.toJson(request);
+ logger.info("ECS Simulator PUT job: {}", body);
restClient.post(url, body).block();
}
import org.oran.dmaapadapter.repository.InfoTypes;
import org.oran.dmaapadapter.repository.Jobs;
import org.oran.dmaapadapter.tasks.ProducerRegstrationTask;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
"app.ecs-base-url=https://localhost:8434" //
})
class IntegrationWithEcs {
- private static final Logger logger = LoggerFactory.getLogger(ApplicationTest.class);
@Autowired
private ApplicationConfig applicationConfig;
main
dmaapmediatorproducer
__debug_bin*
+simulator
+++ /dev/null
-{
- "$schema": "https://json-schema.org/draft/2019-09/schema",
- "title": "STD_Fault_Messages",
- "description": "Schema for job delivering fault messages from DMaaP Message Router",
- "type": "object",
- "properties": {}
-}
\ No newline at end of file
--- /dev/null
+{
+ "types":
+ [
+ {
+ "id": "STD_Fault_Messages",
+ "dmaapTopicUrl": "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/STD_Fault_Messages"
+ }
+ ]
+}
\ No newline at end of file
)
type Config struct {
- LogLevel string
- InfoProducerSupervisionCallbackHost string
- InfoProducerSupervisionCallbackPort int
- InfoJobCallbackHost string
- InfoJobCallbackPort int
- InfoCoordinatorAddress string
+ LogLevel string
+ InfoProducerHost string
+ InfoProducerPort int
+ InfoCoordinatorAddress string
+ MRHost string
+ MRPort int
}
type ProducerRegistrationInfo struct {
func New() *Config {
return &Config{
- LogLevel: getEnv("LOG_LEVEL", "Info"),
- InfoProducerSupervisionCallbackHost: getEnv("INFO_PRODUCER_SUPERVISION_CALLBACK_HOST", ""),
- InfoProducerSupervisionCallbackPort: getEnvAsInt("INFO_PRODUCER_SUPERVISION_CALLBACK_PORT", 8085),
- InfoJobCallbackHost: getEnv("INFO_JOB_CALLBACK_HOST", ""),
- InfoJobCallbackPort: getEnvAsInt("INFO_JOB_CALLBACK_PORT", 8086),
- InfoCoordinatorAddress: getEnv("INFO_COORD_ADDR", "http://enrichmentservice:8083"),
+ LogLevel: getEnv("LOG_LEVEL", "Info"),
+ InfoProducerHost: getEnv("INFO_PRODUCER_HOST", ""),
+ InfoProducerPort: getEnvAsInt("INFO_PRODUCER_PORT", 8085),
+ InfoCoordinatorAddress: getEnv("INFO_COORD_ADDR", "http://enrichmentservice:8083"),
+ MRHost: getEnv("MR_HOST", "http://message-router.onap"),
+ MRPort: getEnvAsInt("MR_PORT", 3904),
}
}
func TestNew_envVarsSetConfigContainSetValues(t *testing.T) {
os.Setenv("LOG_LEVEL", "Debug")
- os.Setenv("INFO_PRODUCER_SUPERVISION_CALLBACK_HOST", "supervisionCallbackHost")
- os.Setenv("INFO_PRODUCER_SUPERVISION_CALLBACK_PORT", "8095")
- os.Setenv("INFO_JOB_CALLBACK_HOST", "jobCallbackHost")
- os.Setenv("INFO_JOB_CALLBACK_PORT", "8096")
+ os.Setenv("INFO_PRODUCER_HOST", "producerHost")
+ os.Setenv("INFO_PRODUCER_PORT", "8095")
os.Setenv("INFO_COORD_ADDR", "infoCoordAddr")
+ os.Setenv("MR_HOST", "mrHost")
+ os.Setenv("MR_PORT", "3908")
t.Cleanup(func() {
os.Clearenv()
})
wantConfig := Config{
- LogLevel: "Debug",
- InfoProducerSupervisionCallbackHost: "supervisionCallbackHost",
- InfoProducerSupervisionCallbackPort: 8095,
- InfoJobCallbackHost: "jobCallbackHost",
- InfoJobCallbackPort: 8096,
- InfoCoordinatorAddress: "infoCoordAddr",
+ LogLevel: "Debug",
+ InfoProducerHost: "producerHost",
+ InfoProducerPort: 8095,
+ InfoCoordinatorAddress: "infoCoordAddr",
+ MRHost: "mrHost",
+ MRPort: 3908,
}
if got := New(); !reflect.DeepEqual(got, &wantConfig) {
t.Errorf("New() = %v, want %v", got, &wantConfig)
var buf bytes.Buffer
log.SetOutput(&buf)
- os.Setenv("INFO_PRODUCER_SUPERVISION_CALLBACK_PORT", "wrong")
+ os.Setenv("INFO_PRODUCER_PORT", "wrong")
t.Cleanup(func() {
log.SetOutput(os.Stderr)
os.Clearenv()
})
wantConfig := Config{
- LogLevel: "Info",
- InfoProducerSupervisionCallbackHost: "",
- InfoProducerSupervisionCallbackPort: 8085,
- InfoJobCallbackHost: "",
- InfoJobCallbackPort: 8086,
- InfoCoordinatorAddress: "http://enrichmentservice:8083",
+ LogLevel: "Info",
+ InfoProducerHost: "",
+ InfoProducerPort: 8085,
+ InfoCoordinatorAddress: "http://enrichmentservice:8083",
+ MRHost: "http://message-router.onap",
+ MRPort: 3904,
}
if got := New(); !reflect.DeepEqual(got, &wantConfig) {
t.Errorf("New() = %v, want %v", got, &wantConfig)
}
logString := buf.String()
- assertions.Contains(logString, "Invalid int value: wrong for variable: INFO_PRODUCER_SUPERVISION_CALLBACK_PORT. Default value: 8085 will be used")
+ assertions.Contains(logString, "Invalid int value: wrong for variable: INFO_PRODUCER_PORT. Default value: 8085 will be used")
}
func TestNew_envVarsNotSetConfigContainDefaultValues(t *testing.T) {
wantConfig := Config{
- LogLevel: "Info",
- InfoProducerSupervisionCallbackHost: "",
- InfoProducerSupervisionCallbackPort: 8085,
- InfoJobCallbackHost: "",
- InfoJobCallbackPort: 8086,
- InfoCoordinatorAddress: "http://enrichmentservice:8083",
+ LogLevel: "Info",
+ InfoProducerHost: "",
+ InfoProducerPort: 8085,
+ InfoCoordinatorAddress: "http://enrichmentservice:8083",
+ MRHost: "http://message-router.onap",
+ MRPort: 3904,
}
if got := New(); !reflect.DeepEqual(got, &wantConfig) {
t.Errorf("New() = %v, want %v", got, &wantConfig)
const registerTypePath = "/data-producer/v1/info-types/"
const registerProducerPath = "/data-producer/v1/info-producers/"
+const typeSchema = `{"type": "object","properties": {},"additionalProperties": false}`
type Registrator interface {
- RegisterTypes(types []*jobs.Type) error
+ RegisterTypes(types []*jobs.TypeData) error
RegisterProducer(producerId string, producerInfo *ProducerRegistrationInfo)
}
}
}
-func (r RegistratorImpl) RegisterTypes(jobTypes []*jobs.Type) error {
+func (r RegistratorImpl) RegisterTypes(jobTypes []jobs.TypeData) error {
for _, jobType := range jobTypes {
- body := fmt.Sprintf(`{"info_job_data_schema": %v}`, jobType.Schema)
+ body := fmt.Sprintf(`{"info_job_data_schema": %v}`, typeSchema)
if error := restclient.Put(r.infoCoordinatorAddress+registerTypePath+url.PathEscape(jobType.TypeId), []byte(body)); error != nil {
return error
}
restclient.Client = &clientMock
- type1 := jobs.Type{
+ type1 := jobs.TypeData{
TypeId: "Type1",
- Schema: `{"title": "Type 1"}`,
}
- types := []*jobs.Type{&type1}
+ types := []jobs.TypeData{type1}
r := NewRegistratorImpl("http://localhost:9990")
err := r.RegisterTypes(types)
assertions.Equal("/data-producer/v1/info-types/Type1", actualRequest.URL.Path)
assertions.Equal("application/json; charset=utf-8", actualRequest.Header.Get("Content-Type"))
body, _ := ioutil.ReadAll(actualRequest.Body)
- expectedBody := []byte(`{"info_job_data_schema": {"title": "Type 1"}}`)
+ expectedBody := []byte(`{"info_job_data_schema": {"type": "object","properties": {},"additionalProperties": false}}`)
assertions.Equal(expectedBody, body)
clientMock.AssertNumberOfCalls(t, "Do", 1)
}
package jobs
import (
+ "encoding/json"
"fmt"
"os"
- "path/filepath"
- "strings"
+ "sync"
+
+ log "github.com/sirupsen/logrus"
+ "oransc.org/nonrtric/dmaapmediatorproducer/internal/restclient"
)
-type Type struct {
- TypeId string
- Schema string
+type TypeDefinitions struct {
+ Types []TypeDefinition `json:"types"`
+}
+type TypeDefinition struct {
+ Id string `json:"id"`
+ DmaapTopicURL string `json:"dmaapTopicUrl"`
+}
+
+type TypeData struct {
+ TypeId string `json:"id"`
+ DMaaPTopicURL string `json:"dmaapTopicUrl"`
+ Jobs map[string]JobInfo
}
type JobInfo struct {
- Owner string `json:"owner"`
- LastUpdated string `json:"last_updated"`
- InfoJobIdentity string `json:"info_job_identity"`
- TargetUri string `json:"target_uri"`
- InfoJobData string `json:"info_job_data"`
- InfoTypeIdentity string `json:"info_type_identity"`
+ Owner string `json:"owner"`
+ LastUpdated string `json:"last_updated"`
+ InfoJobIdentity string `json:"info_job_identity"`
+ TargetUri string `json:"target_uri"`
+ InfoJobData interface{} `json:"info_job_data"`
+ InfoTypeIdentity string `json:"info_type_identity"`
}
type JobHandler interface {
}
var (
- typeDir = "configs"
- Handler JobHandler
- allJobs = make(map[string]map[string]JobInfo)
+ mu sync.Mutex
+ configFile = "configs/type_config.json"
+ Handler JobHandler
+ allTypes = make(map[string]TypeData)
)
func init() {
}
func (jh *jobHandlerImpl) AddJob(ji JobInfo) error {
+ mu.Lock()
+ defer mu.Unlock()
if err := validateJobInfo(ji); err == nil {
- jobs := allJobs[ji.InfoTypeIdentity]
+ jobs := allTypes[ji.InfoTypeIdentity].Jobs
jobs[ji.InfoJobIdentity] = ji
+ log.Debug("Added job: ", ji)
return nil
} else {
return err
}
func validateJobInfo(ji JobInfo) error {
- if _, ok := allJobs[ji.InfoTypeIdentity]; !ok {
+ if _, ok := allTypes[ji.InfoTypeIdentity]; !ok {
return fmt.Errorf("type not supported: %v", ji.InfoTypeIdentity)
}
if ji.InfoJobIdentity == "" {
return nil
}
-func GetTypes() ([]*Type, error) {
- types := make([]*Type, 0, 1)
- err := filepath.Walk(typeDir,
- func(path string, info os.FileInfo, err error) error {
- if err != nil {
- return err
- }
- if strings.Contains(path, ".json") {
- if jobType, err := getType(path); err == nil {
- types = append(types, jobType)
- }
- }
- return nil
- })
+func GetTypes() ([]TypeData, error) {
+ mu.Lock()
+ defer mu.Unlock()
+ types := make([]TypeData, 0, 1)
+ typeDefsByte, err := os.ReadFile(configFile)
+ if err != nil {
+ return nil, err
+ }
+ typeDefs := TypeDefinitions{}
+ err = json.Unmarshal(typeDefsByte, &typeDefs)
if err != nil {
return nil, err
}
+ for _, typeDef := range typeDefs.Types {
+ typeInfo := TypeData{
+ TypeId: typeDef.Id,
+ DMaaPTopicURL: typeDef.DmaapTopicURL,
+ Jobs: make(map[string]JobInfo),
+ }
+ if _, ok := allTypes[typeInfo.TypeId]; !ok {
+ allTypes[typeInfo.TypeId] = typeInfo
+ }
+ types = append(types, typeInfo)
+ }
return types, nil
}
func GetSupportedTypes() []string {
+ mu.Lock()
+ defer mu.Unlock()
supportedTypes := []string{}
- for k := range allJobs {
+ for k := range allTypes {
supportedTypes = append(supportedTypes, k)
}
return supportedTypes
return Handler.AddJob(job)
}
-func getType(path string) (*Type, error) {
- fileName := filepath.Base(path)
- typeName := strings.TrimSuffix(fileName, filepath.Ext(fileName))
+func RunJobs(mRAddress string) {
+ for {
+ pollAndDistributeMessages(mRAddress)
+ }
+}
- if typeSchema, err := os.ReadFile(path); err == nil {
- typeInfo := Type{
- TypeId: typeName,
- Schema: string(typeSchema),
+func pollAndDistributeMessages(mRAddress string) {
+ for typeId, typeInfo := range allTypes {
+ log.Debugf("Processing jobs for type: %v", typeId)
+ messagesBody, error := restclient.Get(fmt.Sprintf("%v/%v", mRAddress, typeInfo.DMaaPTopicURL))
+ if error != nil {
+ log.Warnf("Error getting data from MR. Cause: %v", error)
+ continue
}
- if _, ok := allJobs[typeName]; !ok {
- allJobs[typeName] = make(map[string]JobInfo)
+ distributeMessages(messagesBody, typeInfo)
+ }
+}
+
+func distributeMessages(messages []byte, typeInfo TypeData) {
+ if len(messages) > 2 {
+ mu.Lock()
+ for _, jobInfo := range typeInfo.Jobs {
+ go sendMessagesToConsumer(messages, jobInfo)
}
- return &typeInfo, nil
- } else {
- return nil, err
+ mu.Unlock()
+ }
+}
+
+func sendMessagesToConsumer(messages []byte, jobInfo JobInfo) {
+ log.Debugf("Processing job: %v", jobInfo.InfoJobIdentity)
+ if postErr := restclient.Post(jobInfo.TargetUri, messages); postErr != nil {
+ log.Warnf("Error posting data for job: %v. Cause: %v", jobInfo, postErr)
}
}
func clearAll() {
- allJobs = make(map[string]map[string]JobInfo)
+ allTypes = make(map[string]TypeData)
}
package jobs
import (
+ "bytes"
+ "io/ioutil"
+ "net/http"
"os"
"path/filepath"
+ "sync"
"testing"
+ "time"
"github.com/stretchr/testify/require"
+ "oransc.org/nonrtric/dmaapmediatorproducer/internal/restclient"
)
-const type1Schema = `{"title": "Type 1"}`
+const typeDefinition = `{"types": [{"id": "type1", "dmaapTopicUrl": "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1"}]}`
func TestGetTypes_filesOkShouldReturnSliceOfTypesAndProvideSupportedTypes(t *testing.T) {
assertions := require.New(t)
os.RemoveAll(typesDir)
clearAll()
})
- typeDir = typesDir
- fname := filepath.Join(typesDir, "type1.json")
- if err = os.WriteFile(fname, []byte(type1Schema), 0666); err != nil {
- t.Errorf("Unable to create temporary files for types due to: %v", err)
+ fname := filepath.Join(typesDir, "type_config.json")
+ configFile = fname
+ if err = os.WriteFile(fname, []byte(typeDefinition), 0666); err != nil {
+ t.Errorf("Unable to create temporary config file for types due to: %v", err)
}
types, err := GetTypes()
- wantedType := Type{
- TypeId: "type1",
- Schema: type1Schema,
+ wantedType := TypeData{
+ TypeId: "type1",
+ DMaaPTopicURL: "events/unauthenticated.SEC_FAULT_OUTPUT/dmaapmediatorproducer/type1",
+ Jobs: make(map[string]JobInfo),
}
- wantedTypes := []*Type{&wantedType}
+ wantedTypes := []TypeData{wantedType}
assertions.EqualValues(wantedTypes, types)
assertions.Nil(err)
func TestAddJobWhenTypeIsSupported_shouldAddJobToAllJobsMap(t *testing.T) {
assertions := require.New(t)
- allJobs["type1"] = make(map[string]JobInfo)
- t.Cleanup(func() {
- clearAll()
- })
- jobInfo := JobInfo{
+ wantedJob := JobInfo{
Owner: "owner",
LastUpdated: "now",
InfoJobIdentity: "job1",
InfoJobData: "{}",
InfoTypeIdentity: "type1",
}
+ allTypes["type1"] = TypeData{
+ TypeId: "type1",
+ Jobs: map[string]JobInfo{"job1": wantedJob},
+ }
+ t.Cleanup(func() {
+ clearAll()
+ })
- err := AddJob(jobInfo)
+ err := AddJob(wantedJob)
assertions.Nil(err)
- assertions.Equal(1, len(allJobs["type1"]))
- assertions.Equal(jobInfo, allJobs["type1"]["job1"])
+ assertions.Equal(1, len(allTypes["type1"].Jobs))
+ assertions.Equal(wantedJob, allTypes["type1"].Jobs["job1"])
}
func TestAddJobWhenTypeIsNotSupported_shouldReturnError(t *testing.T) {
func TestAddJobWhenJobIdMissing_shouldReturnError(t *testing.T) {
assertions := require.New(t)
- allJobs["type1"] = make(map[string]JobInfo)
+ allTypes["type1"] = TypeData{
+ TypeId: "type1",
+ }
t.Cleanup(func() {
clearAll()
})
err := AddJob(jobInfo)
assertions.NotNil(err)
- assertions.Equal("missing required job identity: { type1}", err.Error())
+ assertions.Equal("missing required job identity: { <nil> type1}", err.Error())
}
func TestAddJobWhenTargetUriMissing_shouldReturnError(t *testing.T) {
assertions := require.New(t)
- allJobs["type1"] = make(map[string]JobInfo)
+ allTypes["type1"] = TypeData{
+ TypeId: "type1",
+ }
jobInfo := JobInfo{
InfoTypeIdentity: "type1",
InfoJobIdentity: "job1",
err := AddJob(jobInfo)
assertions.NotNil(err)
- assertions.Equal("missing required target URI: { job1 type1}", err.Error())
+ assertions.Equal("missing required target URI: { job1 <nil> type1}", err.Error())
clearAll()
}
+func TestPollAndDistributeMessages(t *testing.T) {
+ assertions := require.New(t)
+ jobInfo := JobInfo{
+ InfoTypeIdentity: "type1",
+ InfoJobIdentity: "job1",
+ TargetUri: "http://consumerHost/target",
+ }
+ allTypes["type1"] = TypeData{
+ TypeId: "type1",
+ DMaaPTopicURL: "topicUrl",
+ Jobs: map[string]JobInfo{"job1": jobInfo},
+ }
+ t.Cleanup(func() {
+ clearAll()
+ })
+
+ wg := sync.WaitGroup{}
+ wg.Add(2) // Two calls should be made to the server, one to poll and one to distribute
+ messages := `[{"message": {"data": "data"}}]`
+ clientMock := NewTestClient(func(req *http.Request) *http.Response {
+ if req.URL.String() == "http://mrAddr/topicUrl" {
+ assertions.Equal(req.Method, "GET")
+ wg.Done()
+ return &http.Response{
+ StatusCode: 200,
+ Body: ioutil.NopCloser(bytes.NewReader([]byte(messages))),
+ Header: make(http.Header), // Must be set to non-nil value or it panics
+ }
+ } else if req.URL.String() == "http://consumerHost/target" {
+ assertions.Equal(req.Method, "POST")
+ assertions.Equal(messages, getBodyAsString(req))
+ assertions.Equal("application/json; charset=utf-8", req.Header.Get("Content-Type"))
+ wg.Done()
+ return &http.Response{
+ StatusCode: 200,
+ Body: ioutil.NopCloser(bytes.NewBufferString(`OK`)),
+ Header: make(http.Header), // Must be set to non-nil value or it panics
+ }
+ }
+ t.Error("Wrong call to client: ", req)
+ t.Fail()
+ return nil
+ })
+
+ restclient.Client = clientMock
+
+ pollAndDistributeMessages("http://mrAddr")
+
+ if waitTimeout(&wg, 100*time.Millisecond) {
+ t.Error("Not all calls to server were made")
+ t.Fail()
+ }
+}
+
+type RoundTripFunc func(req *http.Request) *http.Response
+
+func (f RoundTripFunc) RoundTrip(req *http.Request) (*http.Response, error) {
+ return f(req), nil
+}
+
+//NewTestClient returns *http.Client with Transport replaced to avoid making real calls
+func NewTestClient(fn RoundTripFunc) *http.Client {
+ return &http.Client{
+ Transport: RoundTripFunc(fn),
+ }
+}
+
+// waitTimeout waits for the waitgroup for the specified max timeout.
+// Returns true if waiting timed out.
+func waitTimeout(wg *sync.WaitGroup, timeout time.Duration) bool {
+ c := make(chan struct{})
+ go func() {
+ defer close(c)
+ wg.Wait()
+ }()
+ select {
+ case <-c:
+ return false // completed normally
+ case <-time.After(timeout):
+ return true // timed out
+ }
+}
+
+func getBodyAsString(req *http.Request) string {
+ buf := new(bytes.Buffer)
+ buf.ReadFrom(req.Body)
+ return buf.String()
+}
}
func Put(url string, body []byte) error {
- if req, reqErr := http.NewRequest(http.MethodPut, url, bytes.NewBuffer(body)); reqErr == nil {
+ return do(http.MethodPut, url, body)
+}
+
+func Post(url string, body []byte) error {
+ return do(http.MethodPost, url, body)
+}
+
+func do(method string, url string, body []byte) error {
+ if req, reqErr := http.NewRequest(method, url, bytes.NewBuffer(body)); reqErr == nil {
req.Header.Set("Content-Type", "application/json; charset=utf-8")
if response, respErr := Client.Do(req); respErr == nil {
if isResponseSuccess(response.StatusCode) {
"oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs"
)
+const StatusCallbackPath = "/status"
+const JobsCallbackPath = "/jobs"
+
func StatusHandler(w http.ResponseWriter, r *http.Request) {
- if r.URL.Path != "/" {
+ if r.URL.Path != StatusCallbackPath {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
}
func CreateInfoJobHandler(w http.ResponseWriter, r *http.Request) {
- if r.URL.Path != "/producer_simulator/info_job" {
+ if r.URL.Path != JobsCallbackPath {
http.Error(w, "404 not found.", http.StatusNotFound)
return
}
http.Error(w, fmt.Sprintf("Invalid job info. Cause: %v", err), http.StatusBadRequest)
}
}
-
-func CreateServer(port int, handlerFunc func(http.ResponseWriter, *http.Request)) *http.Server {
-
- mux := http.NewServeMux()
- mux.HandleFunc("/", handlerFunc)
- server := http.Server{
- Addr: fmt.Sprintf(":%v", port), // :{port}
- Handler: mux,
- }
- return &server
-}
"github.com/stretchr/testify/require"
"oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs"
- "oransc.org/nonrtric/dmaapmediatorproducer/mocks"
+ "oransc.org/nonrtric/dmaapmediatorproducer/mocks/jobhandler"
)
func TestStatusHandler(t *testing.T) {
name: "StatusHandler with correct path and method, should return OK",
args: args{
responseRecorder: httptest.NewRecorder(),
- r: newRequest("GET", "/", nil, t),
+ r: newRequest("GET", "/status", nil, t),
},
wantedStatus: http.StatusOK,
wantedBody: "All is well!",
name: "StatusHandler with incorrect method, should return MethodNotAllowed",
args: args{
responseRecorder: httptest.NewRecorder(),
- r: newRequest("PUT", "/", nil, t),
+ r: newRequest("PUT", "/status", nil, t),
},
wantedStatus: http.StatusMethodNotAllowed,
wantedBody: "Method is not supported.\n",
func TestCreateInfoJobHandler(t *testing.T) {
assertions := require.New(t)
- jobHandlerMock := mocks.JobHandler{}
+ jobHandlerMock := jobhandler.JobHandler{}
goodJobInfo := jobs.JobInfo{
Owner: "owner",
name: "CreateInfoJobHandler with correct path and method, should return OK",
args: args{
responseRecorder: httptest.NewRecorder(),
- r: newRequest("POST", "/producer_simulator/info_job", &goodJobInfo, t),
+ r: newRequest("POST", "/jobs", &goodJobInfo, t),
},
wantedStatus: http.StatusOK,
wantedBody: "",
name: "CreateInfoJobHandler with incorrect job info, should return BadRequest",
args: args{
responseRecorder: httptest.NewRecorder(),
- r: newRequest("POST", "/producer_simulator/info_job", &badJobInfo, t),
+ r: newRequest("POST", "/jobs", &badJobInfo, t),
},
wantedStatus: http.StatusBadRequest,
wantedBody: "Invalid job info. Cause: error",
name: "CreateInfoJobHandler with incorrect method, should return MethodNotAllowed",
args: args{
responseRecorder: httptest.NewRecorder(),
- r: newRequest("PUT", "/producer_simulator/info_job", nil, t),
+ r: newRequest("PUT", "/jobs", nil, t),
},
wantedStatus: http.StatusMethodNotAllowed,
wantedBody: "Method is not supported.",
import (
"fmt"
+ "net/http"
"sync"
log "github.com/sirupsen/logrus"
)
var configuration *config.Config
-var supervisionCallbackAddress string
-var jobInfoCallbackAddress string
+var callbackAddress string
func init() {
configuration = config.New()
}
log.Debug("Initializing DMaaP Mediator Producer")
- if configuration.InfoProducerSupervisionCallbackHost == "" {
+ if configuration.InfoProducerHost == "" {
log.Fatal("Missing INFO_PRODUCER_SUPERVISION_CALLBACK_HOST")
}
- supervisionCallbackAddress = fmt.Sprintf("%v:%v", configuration.InfoProducerSupervisionCallbackHost, configuration.InfoProducerSupervisionCallbackPort)
-
- if configuration.InfoJobCallbackHost == "" {
- log.Fatal("Missing INFO_JOB_CALLBACK_HOST")
- }
- jobInfoCallbackAddress = fmt.Sprintf("%v:%v", configuration.InfoJobCallbackHost, configuration.InfoJobCallbackPort)
+ callbackAddress = fmt.Sprintf("%v:%v", configuration.InfoProducerHost, configuration.InfoProducerPort)
registrator := config.NewRegistratorImpl(configuration.InfoCoordinatorAddress)
if types, err := jobs.GetTypes(); err == nil {
log.Fatalf("Unable to get types to register due to: %v", err)
}
producer := config.ProducerRegistrationInfo{
- InfoProducerSupervisionCallbackUrl: supervisionCallbackAddress,
+ InfoProducerSupervisionCallbackUrl: callbackAddress + server.StatusCallbackPath,
SupportedInfoTypes: jobs.GetSupportedTypes(),
- InfoJobCallbackUrl: jobInfoCallbackAddress,
+ InfoJobCallbackUrl: callbackAddress + server.JobsCallbackPath,
}
if err := registrator.RegisterProducer("DMaaP_Mediator_Producer", &producer); err != nil {
log.Fatalf("Unable to register producer due to: %v", err)
log.Debug("Starting DMaaP Mediator Producer")
wg := new(sync.WaitGroup)
- // add two goroutines to `wg` WaitGroup, one for each avilable server
+ // add two goroutines to `wg` WaitGroup, one for each running go routine
wg.Add(2)
- log.Debugf("Starting status callback server at port %v", configuration.InfoProducerSupervisionCallbackPort)
+ log.Debugf("Starting callback server at port %v", configuration.InfoProducerPort)
go func() {
- server := server.CreateServer(configuration.InfoProducerSupervisionCallbackPort, server.StatusHandler)
- log.Warn(server.ListenAndServe())
+ http.HandleFunc(server.StatusCallbackPath, server.StatusHandler)
+ http.HandleFunc(server.JobsCallbackPath, server.CreateInfoJobHandler)
+ log.Warn(http.ListenAndServe(fmt.Sprintf(":%v", configuration.InfoProducerPort), nil))
wg.Done()
}()
go func() {
- server := server.CreateServer(configuration.InfoJobCallbackPort, server.CreateInfoJobHandler)
- log.Warn(server.ListenAndServe())
+ jobs.RunJobs(fmt.Sprintf("%v:%v", configuration.MRHost, configuration.MRPort))
wg.Done()
}()
// Code generated by mockery v2.9.3. DO NOT EDIT.
-package mocks
+package jobhandler
import (
mock "github.com/stretchr/testify/mock"
- jobs "oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs"
+ "oransc.org/nonrtric/dmaapmediatorproducer/internal/jobs"
)
// JobHandler is an autogenerated mock type for the JobHandler type
--- /dev/null
+// -
+// ========================LICENSE_START=================================
+// O-RAN-SC
+// %%
+// Copyright (C) 2021: Nordix Foundation
+// %%
+// Licensed under the Apache License, Version 2.0 (the "License");
+// 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.
+// ========================LICENSE_END===================================
+//
+
+package main
+
+import (
+ "encoding/json"
+ "flag"
+ "fmt"
+ "io"
+ http "net/http"
+
+ "oransc.org/nonrtric/dmaapmediatorproducer/internal/restclient"
+)
+
+func main() {
+ port := flag.Int("port", 40935, "The port this consumer will listen on")
+ flag.Parse()
+ http.HandleFunc("/jobs", handleData)
+
+ fmt.Print("Starting consumer on port: ", *port)
+ http.ListenAndServe(fmt.Sprintf(":%v", *port), nil)
+ registerJob(*port)
+}
+
+func registerJob(port int) {
+ jobInfo := struct {
+ JobOwner string `json:"job_owner"`
+ JobResultUri string `json:"job_result_uri"`
+ InfoTypeId string `json:"info_type_id"`
+ JobDefinition string `json:"job_definition"`
+ }{fmt.Sprintf("test%v", port), fmt.Sprintf("http://localhost:%v/jobs", port), "STD_Fault_Messages", "{}"}
+ fmt.Print("Registering consumer: ", jobInfo)
+ body, _ := json.Marshal(jobInfo)
+ putErr := restclient.Put(fmt.Sprintf("http://localhost:8083/data-consumer/v1/info-jobs/job%v", port), body)
+ if putErr != nil {
+ fmt.Printf("Unable to register consumer: %v", putErr)
+ }
+}
+
+func handleData(w http.ResponseWriter, req *http.Request) {
+ defer req.Body.Close()
+ if reqData, err := io.ReadAll(req.Body); err == nil {
+ fmt.Print("Consumer received body: ", string(reqData))
+ }
+}
ecs_api_edp_delete_type_2 204 type1
ecs_api_edp_get_type_2 404 type1
ecs_api_edp_get_type_ids 200 EMPTY
- ecs_api_edp_put_type_2 201 type1 testdata/ecs/ei-type-1.json
+ if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPE-INFO"* ]]; then
+ ecs_api_edp_put_type_2 201 type1 testdata/ecs/ei-type-1.json testdata/ecs/info-type-info.json
+ else
+ ecs_api_edp_put_type_2 201 type1 testdata/ecs/ei-type-1.json
+ fi
ecs_api_edp_get_type_ids 200 type1
- ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json
+ if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPE-INFO"* ]]; then
+ ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json testdata/ecs/info-type-info.json
+ else
+ ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json
+ fi
ecs_api_edp_put_producer_2 201 prod-a $CB_JOB/prod-a $CB_SV/prod-a type1
ecs_api_edp_put_producer_2 200 prod-a $CB_JOB/prod-a $CB_SV/prod-a type1
if [ $ECS_VERSION == "V1-1" ]; then
ecs_api_edp_get_type 200 type1 testdata/ecs/ei-type-1.json prod-a
else
- ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json
+ if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPE-INFO"* ]]; then
+ ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json testdata/ecs/info-type-info.json
+ else
+ ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json
+ fi
fi
if [ $ECS_VERSION == "V1-1" ]; then
ecs_api_edp_get_type 200 type1 testdata/ecs/ei-type-1.json prod-a
ecs_api_edp_get_type 200 type2 testdata/ecs/ei-type-2.json prod-b
else
- ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json
+ if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPE-INFO"* ]]; then
+ ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json testdata/ecs/info-type-info.json
+ else
+ ecs_api_edp_get_type_2 200 type1 testdata/ecs/ei-type-1.json
+ fi
ecs_api_edp_get_type_2 200 type2 testdata/ecs/ei-type-2.json
fi
cr_equal received_callbacks 12
fi
+# Test job deletion at type delete
+
+if [[ "$ECS_FEATURE_LEVEL" == *"TYPE-SUBSCRIPTIONS"* ]]; then
+
+ ecs_api_edp_delete_type_2 406 type104
+
+ ecs_api_edp_delete_producer 204 prod-id
+
+ ecs_api_edp_delete_type_2 204 type104
+
+ cr_equal received_callbacks 32 30
+ cr_equal received_callbacks?id=info-job108-status 3
+ cr_equal received_callbacks?id=type-status1 19
+ cr_api_check_all_ecs_subscription_events 200 type-status1 type104 testdata/ecs/info-type-4.json DEREGISTERED
+ cr_api_check_all_ecs_events 200 info-job108-status DISABLED
+
+ ecs_api_edp_get_producer 404 prod-id
+
+ ecs_api_idc_get_job 404 job-108
+
+else
+ cr_equal received_callbacks 12
+fi
+
check_ecs_logs
store_logs END
controller_api_get_A1_policy_type 404 OSC ricsim_g1_1 99
RESP=202
- if [ $FLAVOUR == "ONAP" ]; then
+ if [ $FLAVOUR == "ONAP" ] && [[ "$SDNC_FEATURE_LEVEL" != *"TRANS_RESP_CODE"* ]]; then
+ deviation "SDNC does not return original response code from sim"
RESP=200
fi
controller_api_put_A1_policy $RESP OSC ricsim_g1_1 1 4000 testdata/OSC/pi1_template.json
controller_api_put_A1_policy 404 OSC ricsim_g1_1 5 1001 testdata/OSC/pi1_template.json
RESP=201
- if [ $FLAVOUR == "ONAP" ]; then
+ if [ $FLAVOUR == "ONAP" ] && [[ "$SDNC_FEATURE_LEVEL" != *"TRANS_RESP_CODE"* ]]; then
+ deviation "SDNC does not return original response code from sim"
RESP=200
fi
controller_api_put_A1_policy $RESP STD ricsim_g2_1 5000 testdata/STD/pi1_template.json
controller_api_get_A1_policy_status 200 STD ricsim_g2_1 5000 "UNDEFINED"
RESP=202
- if [ $FLAVOUR == "ONAP" ]; then
+ if [ $FLAVOUR == "ONAP" ] && [[ "$SDNC_FEATURE_LEVEL" != *"TRANS_RESP_CODE"* ]]; then
+ deviation "SDNC does not return original response code from sim"
RESP=200
fi
controller_api_delete_A1_policy $RESP OSC ricsim_g1_1 1 4000
RESP=204
- if [ $FLAVOUR == "ONAP" ]; then
+ if [ $FLAVOUR == "ONAP" ] && [[ "$SDNC_FEATURE_LEVEL" != *"TRANS_RESP_CODE"* ]]; then
+ deviation "SDNC does not return original response code from sim"
RESP=200
fi
controller_api_delete_A1_policy $RESP STD ricsim_g2_1 5000
ecs_api_edp_put_type_2 201 type104 testdata/ecs/info-type-4.json
ecs_api_edp_put_type_2 201 type105 testdata/ecs/info-type-5.json
+
+
+ if [[ "$ECS_FEATURE_LEVEL" == *"TYPE-SUBSCRIPTIONS"* ]]; then
+ cr_equal received_callbacks 20 30
+ cr_equal received_callbacks?id=type-status1 10
+ cr_equal received_callbacks?id=type-status2 10
+
+ cr_api_check_all_ecs_subscription_events 200 type-status1 \
+ type1 testdata/ecs/ei-type-1.json REGISTERED \
+ type2 testdata/ecs/ei-type-2.json REGISTERED \
+ type3 testdata/ecs/ei-type-3.json REGISTERED \
+ type4 testdata/ecs/ei-type-4.json REGISTERED \
+ type5 testdata/ecs/ei-type-5.json REGISTERED \
+ type101 testdata/ecs/info-type-1.json REGISTERED \
+ type102 testdata/ecs/info-type-2.json REGISTERED \
+ type103 testdata/ecs/info-type-3.json REGISTERED \
+ type104 testdata/ecs/info-type-4.json REGISTERED \
+ type105 testdata/ecs/info-type-5.json REGISTERED
+
+ cr_api_check_all_ecs_subscription_events 200 type-status2 \
+ type1 testdata/ecs/ei-type-1.json REGISTERED \
+ type2 testdata/ecs/ei-type-2.json REGISTERED \
+ type3 testdata/ecs/ei-type-3.json REGISTERED \
+ type4 testdata/ecs/ei-type-4.json REGISTERED \
+ type5 testdata/ecs/ei-type-5.json REGISTERED \
+ type101 testdata/ecs/info-type-1.json REGISTERED \
+ type102 testdata/ecs/info-type-2.json REGISTERED \
+ type103 testdata/ecs/info-type-3.json REGISTERED \
+ type104 testdata/ecs/info-type-4.json REGISTERED \
+ type105 testdata/ecs/info-type-5.json REGISTERED
+
+ fi
+
ecs_api_edp_put_producer_2 200 prod-a $CB_JOB/prod-a $CB_SV/prod-a type1 type101
ecs_api_edp_put_producer_2 200 prod-b $CB_JOB/prod-b $CB_SV/prod-b type1 type2 type101 type102
fi
+
+if [[ "$ECS_FEATURE_LEVEL" == *"TYPE-SUBSCRIPTIONS"* ]]; then
+
+ ecs_equal json:/data-consumer/v1/info-type-subscription 2 200
+
+ ecs_api_idc_get_subscription_ids 200 owner1 subscription-id-1
+ ecs_api_idc_get_subscription_ids 200 owner2 subscription-id-2
+
+ if [ $use_info_jobs ]; then
+ ecs_equal json:data-producer/v1/info-types 10 1000
+ else
+ ecs_equal json:ei-producer/v1/eitypes 5 1000
+ fi
+
+fi
+
stop_ecs
cr_api_reset
set_ecs_trace
-
if [[ "$ECS_FEATURE_LEVEL" == *"TYPE-SUBSCRIPTIONS"* ]]; then
- ecs_api_idc_get_subscription_ids 200 NOOWNER EMPTY
- ecs_api_idc_get_subscription_ids 200 NOOWNER EMPTY
+ ecs_equal json:/data-consumer/v1/info-type-subscription 2 200
+
+ ecs_api_idc_get_subscription_ids 200 owner1 subscription-id-1
+ ecs_api_idc_get_subscription_ids 200 owner2 subscription-id-2
if [ $use_info_jobs ]; then
ecs_equal json:data-producer/v1/info-types 10 1000
else
ecs_equal json:ei-producer/v1/eitypes 5 1000
fi
-
- ecs_api_idc_put_subscription 201 subscription-id-1 owner1 $TYPESTATUS1
-
- ecs_api_idc_get_subscription_ids 200 owner1 subscription-id-1
-
- ecs_api_idc_put_subscription 201 subscription-id-2 owner2 $TYPESTATUS2
-
- ecs_api_idc_get_subscription_ids 200 owner2 subscription-id-2
-
fi
+cr_equal received_callbacks 0
+
for ((i=1; i<=$NUM_JOBS; i++))
do
if [ $(($i%5)) -eq 0 ]; then
ecs_equal json:data-consumer/v1/info-jobs?infoTypeId=type105 0
fi
+if [ $use_info_jobs ]; then
+ if [[ "$ECS_FEATURE_LEVEL" == *"TYPE-SUBSCRIPTIONS"* ]]; then
+ ecs_api_edp_put_type_2 200 type101 testdata/ecs/info-type-1.json
+ ecs_api_edp_put_type_2 200 type102 testdata/ecs/info-type-2.json
+ ecs_api_edp_put_type_2 200 type103 testdata/ecs/info-type-3.json
+ ecs_api_edp_put_type_2 200 type104 testdata/ecs/info-type-4.json
+ ecs_api_edp_put_type_2 200 type105 testdata/ecs/info-type-5.json
+ fi
+fi
+
if [[ "$ECS_FEATURE_LEVEL" == *"TYPE-SUBSCRIPTIONS"* ]]; then
- cr_equal received_callbacks 0 30
+ cr_equal received_callbacks 10 30
+ cr_equal received_callbacks?id=type-status1 5
+ cr_equal received_callbacks?id=type-status2 5
+
+ cr_api_check_all_ecs_subscription_events 200 type-status1 \
+ type101 testdata/ecs/info-type-1.json REGISTERED \
+ type102 testdata/ecs/info-type-2.json REGISTERED \
+ type103 testdata/ecs/info-type-3.json REGISTERED \
+ type104 testdata/ecs/info-type-4.json REGISTERED \
+ type105 testdata/ecs/info-type-5.json REGISTERED
+
+ cr_api_check_all_ecs_subscription_events 200 type-status2 \
+ type101 testdata/ecs/info-type-1.json REGISTERED \
+ type102 testdata/ecs/info-type-2.json REGISTERED \
+ type103 testdata/ecs/info-type-3.json REGISTERED \
+ type104 testdata/ecs/info-type-4.json REGISTERED \
+ type105 testdata/ecs/info-type-5.json REGISTERED
+
else
cr_equal received_callbacks 0 30
fi
--- /dev/null
+#!/usr/bin/env bash
+
+# ============LICENSE_START===============================================
+# Copyright (C) 2020 Nordix Foundation. All rights reserved.
+# ========================================================================
+# Licensed under the Apache License, Version 2.0 (the "License");
+# 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.
+# ============LICENSE_END=================================================
+#
+
+TC_ONELINE_DESCR="Testing southbound proxy for SDNC - docker only"
+
+#App names to include in the test when running docker, space separated list
+DOCKER_INCLUDED_IMAGES="RICSIM SDNC HTTPPROXY"
+#App names to include in the test when running kubernetes, space separated list
+KUBE_INCLUDED_IMAGES=""
+#Prestarted app (not started by script) to include in the test when running kubernetes, space separated list
+KUBE_PRESTARTED_IMAGES=" "
+
+#Supported test environment profiles
+SUPPORTED_PROFILES="ONAP-ISTANBUL"
+#Supported run modes
+SUPPORTED_RUNMODES="DOCKER"
+
+. ../common/testcase_common.sh $@
+. ../common/controller_api_functions.sh
+. ../common/ricsimulator_api_functions.sh
+. ../common/kube_proxy_api_functions.sh
+. ../common/http_proxy_api_functions.sh
+
+setup_testenvironment
+
+#### TEST BEGIN ####
+
+generate_policy_uuid
+
+#Test agent and simulator protocol versions (others are http only)
+NB_TESTED_PROTOCOLS="HTTP HTTPS"
+SB_TESTED_PROTOCOLS="HTTP HTTPS"
+
+for __nb_httpx in $NB_TESTED_PROTOCOLS ; do
+ for __sb_httpx in $SB_TESTED_PROTOCOLS ; do
+
+ echo "#####################################################################"
+ echo "#####################################################################"
+ echo "### Testing SDNC using Northbound: $__nb_httpx and Southbound: $__sb_httpx"
+ echo "#####################################################################"
+ echo "#####################################################################"
+
+ if [ $__sb_httpx == "HTTPS" ]; then
+ deviation "Southbound https proxy is currently not supported"
+ break
+ fi
+
+
+ # Clean container and start all needed containers #
+ clean_environment
+
+ start_http_proxy
+
+ start_ric_simulators ricsim_g1 1 OSC_2.1.0
+ start_ric_simulators ricsim_g2 1 STD_1.1.3
+ if [ "$PMS_VERSION" == "V2" ]; then
+ start_ric_simulators ricsim_g3 1 STD_2.0.0
+ fi
+
+ start_sdnc
+
+ if [ $__nb_httpx == "HTTPS" ]; then
+ # "Using secure ports towards SDNC"
+ use_sdnc_https
+ else
+ #"Using non-secure ports towards SDNC"
+ use_sdnc_http
+ fi
+
+ if [ $__sb_httpx == "HTTPS" ]; then
+ # "Using secure ports towards SDNC"
+ use_simulator_https
+ use_http_proxy_https
+ else
+ #"Using non-secure ports towards SDNC"
+ use_simulator_http
+ use_http_proxy_http
+ fi
+
+ echo -e $BOLD"Configure proxy in SDNC"$EBOLD
+ echo ""
+
+ if [ $__sb_httpx == "HTTPS" ]; then
+ echo "
+ sed -i 's/a1Mediator.proxy.url=/a1Mediator.proxy.url=https:\/\/httpproxy:8433/g' /opt/onap/ccsdk/data/properties/a1-adapter-api-dg.properties
+ " | docker exec -i a1controller bash
+ else
+ echo "
+ sed -i 's/a1Mediator.proxy.url=/a1Mediator.proxy.url=http:\/\/httpproxy:8080/g' /opt/onap/ccsdk/data/properties/a1-adapter-api-dg.properties
+ " | docker exec -i a1controller bash
+ fi
+
+ # Restart SDNC to use the updated config
+ stop_sdnc
+ start_stopped_sdnc
+
+ # API tests
+
+ controller_api_get_A1_policy_type 404 OSC ricsim_g1_1 1
+
+ sim_put_policy_type 201 ricsim_g1_1 1 testdata/OSC/sim_1.json
+
+
+ controller_api_get_A1_policy_ids 200 OSC ricsim_g1_1 1
+ controller_api_get_A1_policy_ids 200 STD ricsim_g2_1
+
+ controller_api_get_A1_policy_type 200 OSC ricsim_g1_1 1
+ controller_api_get_A1_policy_type 200 OSC ricsim_g1_1 1 testdata/OSC/sim_1.json
+ controller_api_get_A1_policy_type 404 OSC ricsim_g1_1 99
+
+ controller_api_put_A1_policy 202 OSC ricsim_g1_1 1 4000 testdata/OSC/pi1_template.json
+ controller_api_put_A1_policy 404 OSC ricsim_g1_1 5 1001 testdata/OSC/pi1_template.json
+
+ controller_api_put_A1_policy 201 STD ricsim_g2_1 5000 testdata/STD/pi1_template.json
+
+ controller_api_get_A1_policy_ids 200 OSC ricsim_g1_1 1 4000
+ controller_api_get_A1_policy_ids 200 STD ricsim_g2_1 5000
+
+ controller_api_get_A1_policy_status 200 OSC ricsim_g1_1 1 4000
+ controller_api_get_A1_policy_status 200 STD ricsim_g2_1 5000
+
+ VAL='NOT IN EFFECT'
+ controller_api_get_A1_policy_status 200 OSC ricsim_g1_1 1 4000 "$VAL" "false"
+ controller_api_get_A1_policy_status 200 STD ricsim_g2_1 5000 "UNDEFINED"
+
+
+ deviation "SDNC does not return original response code from sim"
+ controller_api_delete_A1_policy 202 OSC ricsim_g1_1 1 4000
+
+ deviation "SDNC does not return original response code from sim"
+ controller_api_delete_A1_policy 204 STD ricsim_g2_1 5000
+
+ sim_contains_str ricsim_g1_1 remote_hosts httpproxy.nonrtric-docker-net
+ sim_contains_str ricsim_g2_1 remote_hosts httpproxy.nonrtric-docker-net
+
+ check_sdnc_logs
+
+ store_logs "NB_"$__nb_httpx"_SB_"$__sb_httpx
+
+ done
+
+done
+
+#### TEST COMPLETE ####
+
+print_result
+
+auto_clean_environment
\ No newline at end of file
--- /dev/null
+{
+ "hint": "periodic"
+}
\ No newline at end of file
return 0
}
+
+# Stop the sndc
+# args: -
+# args: -
+# (Function for test scripts)
+stop_sdnc() {
+ echo -e $BOLD"Stopping $SDNC_DISPLAY_NAME"$EBOLD
+
+ if [ $RUNMODE == "KUBE" ]; then
+ __log_conf_fail_not_supported " Cannot stop sndc in KUBE mode"
+ return 1
+ else
+ docker stop $SDNC_APP_NAME &> ./tmp/.dockererr
+ if [ $? -ne 0 ]; then
+ __print_err "Could not stop $SDNC_APP_NAME" $@
+ cat ./tmp/.dockererr
+ ((RES_CONF_FAIL++))
+ return 1
+ fi
+ fi
+ echo -e $BOLD$GREEN"Stopped"$EGREEN$EBOLD
+ echo ""
+ return 0
+}
+
+# Start a previously stopped sdnc
+# args: -
+# (Function for test scripts)
+start_stopped_sdnc() {
+ echo -e $BOLD"Starting (the previously stopped) $SDNC_DISPLAY_NAME"$EBOLD
+
+ if [ $RUNMODE == "KUBE" ]; then
+ __log_conf_fail_not_supported " Cannot restart sndc in KUBE mode"
+ return 1
+ else
+ docker start $SDNC_APP_NAME &> ./tmp/.dockererr
+ if [ $? -ne 0 ]; then
+ __print_err "Could not start (the stopped) $SDNC_APP_NAME" $@
+ cat ./tmp/.dockererr
+ ((RES_CONF_FAIL++))
+ return 1
+ fi
+ fi
+ __check_service_start $SDNC_APP_NAME $SDNC_PATH$SDNC_ALIVE_URL
+ if [ $? -ne 0 ]; then
+ return 1
+ fi
+ echo ""
+ return 0
+}
+
# Check the agent logs for WARNINGs and ERRORs
# args: -
# (Function for test scripts)
# API Test function: GET /ei-producer/v1/eitypes/{eiTypeId}
# API Test function: GET /data-producer/v1/info-types/{infoTypeId}
-# args: (v1_2) <response-code> <type-id> [<job-schema-file> ]
+# args: (v1_2) <response-code> <type-id> [<job-schema-file> [ <info-type-info> ]]
# (Function for test scripts)
ecs_api_edp_get_type_2() {
__log_test_start $@
if [ $# -eq 3 ]; then
paramError=0
fi
+ if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPE-INFO"* ]]; then
+ if [ $# -eq 4 ]; then
+ paramError=0
+ fi
+ fi
if [ $paramError -ne 0 ]; then
- __print_err "<response-code> <type-id> [<job-schema-file> ]" $@
+ __print_err "<response-code> <type-id> [<job-schema-file> [ <info-type-info> ]]" $@
return 1
fi
if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPES"* ]]; then
__log_test_fail_status_code $1 $status
return 1
fi
- if [ $# -eq 3 ]; then
+ if [ $# -ge 3 ]; then
body=${res:0:${#res}-3}
if [ -f $3 ]; then
__log_test_fail_general "Job template file "$3", does not exist"
return 1
fi
+ info_data=""
+ if [ $# -gt 3 ]; then
+ if [ -f $4 ]; then
+ info_data=$(cat $4)
+ else
+ __log_test_fail_general "Info-data file "$4", does not exist"
+ return 1
+ fi
+ info_data=",\"info_type_information\":$info_data"
+ fi
if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPES"* ]]; then
- targetJson="{\"info_job_data_schema\":$schema}"
+ targetJson="{\"info_job_data_schema\":$schema $info_data}"
else
targetJson="{\"ei_job_data_schema\":$schema}"
fi
# API Test function: PUT /ei-producer/v1/eitypes/{eiTypeId}
# API Test function: PUT /data-producer/v1/info-types/{infoTypeId}
-# args: (v1_2) <response-code> <type-id> <job-schema-file>
+# args: (v1_2) <response-code> <type-id> <job-schema-file> [ <info-type-info> ]
# (Function for test scripts)
ecs_api_edp_put_type_2() {
__log_test_start $@
- if [ $# -ne 3 ]; then
- __print_err "<response-code> <type-id> <job-schema-file>" $@
- return 1
+ if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPE-INFO"* ]]; then
+ if [ $# -lt 3 ] || [ $# -gt 4 ]; then
+ __print_err "<response-code> <type-id> <job-schema-file> [ <info-type-info> ]" $@
+ return 1
+ fi
+ else
+ if [ $# -ne 3 ]; then
+ __print_err "<response-code> <type-id> <job-schema-file>" $@
+ return 1
+ fi
fi
if [ ! -f $3 ]; then
__log_test_fail_general "Job schema file "$3", does not exist"
return 1
fi
+
+ info_data=""
+ if [ $# -gt 3 ]; then
+ if [ -f $4 ]; then
+ info_data=$(cat $4)
+ else
+ __log_test_fail_general "Info-data file "$4", does not exist"
+ return 1
+ fi
+ info_data=",\"info_type_information\":$info_data"
+ fi
+
if [[ "$ECS_FEATURE_LEVEL" == *"INFO-TYPES"* ]]; then
schema=$(cat $3)
- input_json="{\"info_job_data_schema\":$schema}"
+ input_json="{\"info_job_data_schema\":$schema $info_data}"
file="./tmp/put_type.json"
echo $input_json > $file
# SDNC A1 Controller remote image and tag
SDNC_A1_CONTROLLER_IMAGE_BASE="onap/sdnc-image"
-SDNC_A1_CONTROLLER_IMAGE_TAG_LOCAL="2.1.3-SNAPSHOT" ###CHECK THIS
-SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_SNAPSHOT="2.1.3-STAGING-latest"
-SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE="2.1.3-STAGING-latest" #Will use snapshot repo
-SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE="2.1.2"
+SDNC_A1_CONTROLLER_IMAGE_TAG_LOCAL="2.1.7-SNAPSHOT" ###CHECK THIS
+SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_SNAPSHOT="2.1.7-STAGING-latest"
+SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE="2.1.7-STAGING-latest" #Will use snapshot repo
+SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE="2.1.6"
#SDNC DB remote image and tag
#The DB is part of SDNC so handled in the same way as SDNC
SDNC_KARAF_LOG="/opt/opendaylight/data/log/karaf.log" # Path to karaf log
#SDNC_RESPONSE_JSON_KEY="A1-ADAPTER-API:output" # Key name for output json in replies from sdnc (for upgraded sdnc)
SDNC_RESPONSE_JSON_KEY="output" # Key name for output json in replies from sdnc
+SDNC_FEATURE_LEVEL="" # Space separated list of features
RAPP_CAT_APP_NAME="rappcatalogueservice" # Name for the RAPP Catalogue
RAPP_CAT_DISPLAY_NAME="RAPP Catalogue Service"
# Policy Agent image and tags
POLICY_AGENT_IMAGE_BASE="onap/ccsdk-oran-a1policymanagementservice"
-POLICY_AGENT_IMAGE_TAG_LOCAL="1.2.1-SNAPSHOT"
-POLICY_AGENT_IMAGE_TAG_REMOTE_SNAPSHOT="1.2.1-SNAPSHOT"
-POLICY_AGENT_IMAGE_TAG_REMOTE="1.2.1-STAGING-latest" #Will use snapshot repo
+POLICY_AGENT_IMAGE_TAG_LOCAL="1.2.2-SNAPSHOT"
+POLICY_AGENT_IMAGE_TAG_REMOTE_SNAPSHOT="1.2-SNAPSHOT"
+POLICY_AGENT_IMAGE_TAG_REMOTE="1.2.2-STAGING-latest" #Will use snapshot repo
POLICY_AGENT_IMAGE_TAG_REMOTE_RELEASE="1.2.1"
# SDNC A1 Controller remote image and tag
SDNC_DB_IMAGE_BASE="mariadb"
SDNC_DB_IMAGE_TAG_REMOTE_PROXY="10.5"
-# ECS image and tag - uses cherry release
+# ECS image and tag - uses d release
ECS_IMAGE_BASE="o-ran-sc/nonrtric-enrichment-coordinator-service"
-ECS_IMAGE_TAG_REMOTE_RELEASE_ORAN="1.0.1"
+ECS_IMAGE_TAG_REMOTE_RELEASE_ORAN="1.1.0"
#Note: Update var ECS_FEATURE_LEVEL if image version is changed
-# Control Panel image and tag - uses cherry release
+# Control Panel image and tag - uses d release
CONTROL_PANEL_IMAGE_BASE="o-ran-sc/nonrtric-controlpanel"
-CONTROL_PANEL_IMAGE_TAG_REMOTE_RELEASE_ORAN="2.1.1"
+CONTROL_PANEL_IMAGE_TAG_REMOTE_RELEASE_ORAN="2.2.0"
+# Gateway image and tags - uses d release
+NRT_GATEWAY_IMAGE_BASE="o-ran-sc/nonrtric-gateway"
+NRT_GATEWAY_IMAGE_TAG_REMOTE_RELEASE_ORAN="1.0.0"
-# RAPP Catalogue image and tags - uses cherry release
+# RAPP Catalogue image and tags - uses d release
RAPP_CAT_IMAGE_BASE="o-ran-sc/nonrtric-r-app-catalogue"
RAPP_CAT_IMAGE_TAG_REMOTE_RELEASE_ORAN="1.0.1"
-# Near RT RIC Simulator image and tags - uses cherry release
+# Near RT RIC Simulator image and tags - uses d release
RIC_SIM_IMAGE_BASE="o-ran-sc/a1-simulator"
RIC_SIM_IMAGE_TAG_REMOTE_RELEASE_ORAN="2.1.0"
PROJECT_IMAGES_APP_NAMES="PA SDNC"
# List of app short names which images pulled from ORAN
-ORAN_IMAGES_APP_NAMES="CP ECS RICSIM RC"
+ORAN_IMAGES_APP_NAMES="CP ECS RICSIM RC NGW"
# List of app short names which images pulled from ONAP
ONAP_IMAGES_APP_NAMES="" # Not used
ECS_CONFIG_MOUNT_PATH=/opt/app/enrichment-coordinator-service/config # Internal container path for configuration
ECS_CONFIG_FILE=application.yaml # Config file name
ECS_VERSION="V1-2" # Version where the types are added in the producer registration
-ECS_FEATURE_LEVEL="" # Space separated list of features
+ECS_FEATURE_LEVEL="INFO-TYPES" # Space separated list of features
MR_DMAAP_APP_NAME="dmaap-mr" # Name for the Dmaap MR
MR_STUB_APP_NAME="mr-stub" # Name of the MR stub
SDNC_KARAF_LOG="/opt/opendaylight/data/log/karaf.log" # Path to karaf log
#SDNC_RESPONSE_JSON_KEY="A1-ADAPTER-API:output" # Key name for output json in replies from sdnc (for upgraded sdnc)
SDNC_RESPONSE_JSON_KEY="output" # Key name for output json in replies from sdnc
+SDNC_FEATURE_LEVEL="TRANS_RESP_CODE" # Space separated list of features
+ # TRANS_RESP_CODE: SDNC return southbound response code
RAPP_CAT_APP_NAME="rappcatalogueservice" # Name for the RAPP Catalogue
RAPP_CAT_DISPLAY_NAME="RAPP Catalogue Service"
CONTROL_PANEL_CONFIG_FILE=application.properties # Config file name
CONTROL_PANEL_HOST_MNT_DIR="./mnt" # Mounted dir, relative to compose file, on the host
+NRT_GATEWAY_APP_NAME="nonrtricgateway" # Name of the Gateway container
+NRT_GATEWAY_DISPLAY_NAME="NonRT-RIC Gateway"
+NRT_GATEWAY_EXTERNAL_PORT=9090 # Gateway container external port (host -> container)
+NRT_GATEWAY_INTERNAL_PORT=9090 # Gateway container internal port (container -> container)
+NRT_GATEWAY_EXTERNAL_SECURE_PORT=9091 # Gateway container external port (host -> container)
+NRT_GATEWAY_INTERNAL_SECURE_PORT=9091 # Gateway container internal port (container -> container)
+NRT_GATEWAY_LOGPATH="/var/log/nonrtric-gateway/application.log" # Path the application log in the Gateway container
+NRT_GATEWAY_HOST_MNT_DIR="./mnt" # Mounted dir, relative to compose file, on the host
+NRT_GATEWAY_ALIVE_URL="/actuator/metrics" # Base path for alive check
+NRT_GATEWAY_COMPOSE_DIR="ngw" # Dir in simulator_group for docker-compose
+NRT_GATEWAY_CONFIG_MOUNT_PATH=/opt/app/nonrtric-gateway/config # Container internal path for config
+NRT_GATEWAY_CONFIG_FILE=application.yaml # Config file name
+NRT_GATEWAY_PKG_NAME="org.springframework.cloud.gateway" # Java base package name
+NRT_GATEWAY_ACTUATOR="/actuator/loggers/$NRT_GATEWAY_PKG_NAME" # Url for trace/debug
+
HTTP_PROXY_APP_NAME="httpproxy" # Name of the Http Proxy container
HTTP_PROXY_DISPLAY_NAME="Http Proxy"
HTTP_PROXY_EXTERNAL_PORT=8740 # Http Proxy container external port (host -> container)
NRT_GATEWAY_IMAGE_TAG_REMOTE_RELEASE="1.0.0"
-# SDNC A1 Controller image and tags - Note using ONAP image
+# SDNC A1 Controller image and tags - Note using Honolulu ONAP image
SDNC_A1_CONTROLLER_IMAGE_BASE="onap/sdnc-image"
-SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE_ONAP="2.1.2"
+SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE_ONAP="2.1.6"
#No local image for ONAP SDNC, remote release image always used
# ORAN SDNC adapter kept as reference
SDNC_KARAF_LOG="/opt/opendaylight/data/log/karaf.log" # Path to karaf log
#SDNC_RESPONSE_JSON_KEY="A1-ADAPTER-API:output" # Key name for output json in replies from sdnc (for upgraded sdnc)
SDNC_RESPONSE_JSON_KEY="output" # Key name for output json in replies from sdnc
+SDNC_FEATURE_LEVEL="" # Space separated list of features
RAPP_CAT_APP_NAME="rappcatalogueservice" # Name for the RAPP Catalogue
RAPP_CAT_DISPLAY_NAME="RAPP Catalogue"
NRT_GATEWAY_IMAGE_TAG_REMOTE_RELEASE="1.1.0"
-# SDNC A1 Controller image and tags - Note using ONAP image
+# SDNC A1 Controller image and tags - Note using released honolulu ONAP image
SDNC_A1_CONTROLLER_IMAGE_BASE="onap/sdnc-image"
-SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE_ONAP="2.1.2"
+SDNC_A1_CONTROLLER_IMAGE_TAG_REMOTE_RELEASE_ONAP="2.1.6"
#No local image for ONAP SDNC, remote release image always used
# ORAN SDNC adapter kept as reference
ECS_CONFIG_MOUNT_PATH=/opt/app/enrichment-coordinator-service/config # Internal container path for configuration
ECS_CONFIG_FILE=application.yaml # Config file name
ECS_VERSION="V1-2" # Version where the types are decoupled from the producer registration
-ECS_FEATURE_LEVEL="INFO-TYPES TYPE-SUBSCRIPTIONS" # Space separated list of features
+ECS_FEATURE_LEVEL="INFO-TYPES TYPE-SUBSCRIPTIONS INFO-TYPE-INFO" # Space separated list of features
MR_DMAAP_APP_NAME="dmaap-mr" # Name for the Dmaap MR
MR_STUB_APP_NAME="mr-stub" # Name of the MR stub
SDNC_KARAF_LOG="/opt/opendaylight/data/log/karaf.log" # Path to karaf log
#SDNC_RESPONSE_JSON_KEY="A1-ADAPTER-API:output" # Key name for output json in replies from sdnc (for upgraded sdnc)
SDNC_RESPONSE_JSON_KEY="output" # Key name for output json in replies from sdnc
+SDNC_FEATURE_LEVEL="" # Space separated list of features
RAPP_CAT_APP_NAME="rappcatalogueservice" # Name for the RAPP Catalogue
RAPP_CAT_DISPLAY_NAME="RAPP Catalogue"
__check_stop_at_error
}
+# Function to log a configuration that is not supported
+__log_conf_fail_not_supported() {
+ echo -e $RED" FAIL, function not supported"$ERED$@
+ ((RES_CONF_FAIL++))
+ __print_current_stats
+ __check_stop_at_error
+}
+
# Function to log a passed configuration setup
__log_conf_ok() {
if [ $# -gt 0 ]; then
# The HTTP proxy (if configured) will only be used for accessing NearRT RIC:s
http.proxy-host: $AGENT_HTTP_PROXY_CONFIG_HOST_NAME
http.proxy-port: $AGENT_HTTP_PROXY_CONFIG_PORT
+ http.proxy-type: HTTP