diff --git a/.obsidian/snippets/.vscode/settings.json b/.obsidian/snippets/.vscode/settings.json new file mode 100644 index 0000000..dc9a84c --- /dev/null +++ b/.obsidian/snippets/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "chat.disableAIFeatures": true +} \ No newline at end of file diff --git a/.obsidian/snippets/pdf-export.css b/.obsidian/snippets/pdf-export.css index 1e02531..aa5a947 100644 --- a/.obsidian/snippets/pdf-export.css +++ b/.obsidian/snippets/pdf-export.css @@ -42,8 +42,7 @@ white-space: pre-wrap !important; /* Forces text to wrap if it's still too long, .markdown-rendered h3, .markdown-rendered h4, .markdown-rendered h5, - .markdown-rendered h6, - .markdown-rendered p { + .markdown-rendered h6 { break-after: avoid !important; page-break-after: avoid !important; } diff --git a/.obsidian/workspace-mobile.json b/.obsidian/workspace-mobile.json index d60e705..0308942 100644 --- a/.obsidian/workspace-mobile.json +++ b/.obsidian/workspace-mobile.json @@ -14,7 +14,7 @@ "type": "markdown", "state": { "file": "Semester 2/EIST/EIST CHEATSHEET.md", - "mode": "source", + "mode": "preview", "source": false }, "icon": "lucide-file", diff --git a/.obsidian/workspace.json b/.obsidian/workspace.json index 80ac0dc..bbcde8d 100644 --- a/.obsidian/workspace.json +++ b/.obsidian/workspace.json @@ -4,18 +4,18 @@ "type": "split", "children": [ { - "id": "844a1764731992eb", + "id": "a54102d9f9827d40", "type": "tabs", "children": [ { - "id": "3ba46ad009838dd8", + "id": "d315e70358bc75ab", "type": "leaf", "state": { "type": "markdown", "state": { "file": "Semester 2/EIST/EIST CHEATSHEET.md", "mode": "source", - "source": true + "source": false }, "icon": "lucide-file", "title": "EIST CHEATSHEET" @@ -157,7 +157,7 @@ "type": "outline", "state": { "file": "Semester 2/EIST/EIST CHEATSHEET.md", - "followCursor": false, + "followCursor": true, "showSearch": false, "searchQuery": "" }, @@ -206,10 +206,11 @@ "bases:Create new base": false } }, - "active": "3ba46ad009838dd8", + "active": "1221778bf93051e6", "lastOpenFiles": [ - "Semester 2/EIST/Progress.md", "Semester 2/EIST/EIST CHEATSHEET.md", + "Semester 2/EIST CHEATSHEET.pdf", + "Semester 2/EIST/Progress.md", "Semester 2/EIST/EIST CHEATSHEET.pdf", "2026-07-10.md", "Semester 2/EIST/lu280859klubr.tmp", @@ -223,7 +224,6 @@ "Excalidraw/Drawing 2026-07-09 18.02.06.excalidraw.md", "Excalidraw", "home/nikola/Documents/EIST/eist26l09p01-go38coz.md", - "home/nikola/Documents/EIST", "file/home/nikola/Documents/EIST/eist26l09p01-go38coz 3.md", "file/home/nikola/Documents/EIST/eist26l09p01-go38coz 2.md", "file/home/nikola/Documents/EIST/eist26l09p01-go38coz 1.md", diff --git a/Semester 2/EIST CHEATSHEET.pdf b/Semester 2/EIST CHEATSHEET.pdf new file mode 100644 index 0000000..8d2f64c Binary files /dev/null and b/Semester 2/EIST CHEATSHEET.pdf differ diff --git a/Semester 2/EIST/EIST CHEATSHEET.md b/Semester 2/EIST/EIST CHEATSHEET.md index ba310a4..255c96f 100644 --- a/Semester 2/EIST/EIST CHEATSHEET.md +++ b/Semester 2/EIST/EIST CHEATSHEET.md @@ -1,9 +1,10 @@ # List of contents 1. [[#REST API with Spring]] 2. [[#Flask API in Python]] -3. [[#DOCKER]] -4. [[#gRPC]] -5. +3. [[#gRPC]] +4. [[#JUnit]] +5. [[#EasyMock]] +6. [[#DOCKER]]
@@ -450,48 +451,6 @@ for x, y in thisdict.items(): # Looping over key-value pairs as tuples | setdefault() | Returns the value of the specified key. If the key does not exist: insert the key, with the specified value | | update() | Updates the dictionary with the specified key-value pairs | | values() | Returns a list of all the values in the dictionary | -
-# DOCKER - -**Docker reference: https://docs.docker.com/** - -### Dockerfiles -https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/ -https://docs.docker.com/reference/dockerfile/ - -```dockerfile -FROM python:3.13 -WORKDIR /usr/local/app - -# Install the application dependencies -COPY requirements.txt ./ -RUN pip install --no-cache-dir -r requirements.txt - -# Copy in the source code -COPY src ./src -EXPOSE 8080 - -# Setup an app user so the container doesn't run as the root user -RUN useradd app -USER app - -CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"] -``` - -### Building docker - -```bash -docker build -t -``` - -### Docker processes -```bash -docker ps -``` -#### Exercises -- [L09P01 - Registry Office Service Deployment](file:///home/nikola/Documents/EIST/eist26l09p01-go38coz) -- [L09P02 - Garching Best Software](file:///home/nikola/Documents/EIST/eist26l09p02-go38coz) -- [L08PE04 - Spaceship](file:///home/nikola/Documents/EIST/eist26l0pe04-go38coz)
@@ -768,7 +727,162 @@ public String displayPlaylist(int[] playlist) throws SpotifyClientException { - L02PB01 Weather Reporter - L02P01 Spotify gRPC - L03PE03 Gobblemaps +# JUnit +## assertThrows() +```java +@Test +public void testSetOnlineCourseUrlWithInvalidUrl() { + OnlineCourse course = new OnlineCourse("test"); + // You need to pass the CLASS of the exception and a runnable which calls the function + // then the test will pass if EXACTLY this exception is throwed + // If you want to test for any exception pass Exception.class however, that is usually discouraged and not needed + assertThrows(MalformedURLException.class,() -> course.setUrl("hjdahjsd")); +} +``` +## assertDoesNotThrow() +```java +@Test +public void testSetOnlineCourseUrlWithValidUrl(){ + OnlineCourse course = new OnlineCourse("test"); + // Simply assertDoesNotThrow with a runnable + assertDoesNotThrow(() -> course.setUrl("https://test")); + + // We need to handle constructor of URL throwing an exception despite knowing that it won't as we are passing it a correct URL + try { + assertEquals(new URL("https://test"),course.getUrl()); + } catch (MalformedURLException e) { + } +} +``` +# EasyMock + +`@TestSubject` annotations automatically calls the constructor with the mockObjects. However it is not applicable for constructors with other parameters that are not mocked(for example primitive types). In such cases you can call the constructor of the **test subject** as usual inside the test or in a @Before method or wherever you want. + +**Second example contains how to expect *void* method calls** +## Example with TestSubject + +```java +// Needs to extend the tests with EasyMock +@ExtendWith(EasyMockExtension.class) +class DiscussionTest { + + // TestSubject annotations automatically calls the constructor with the mockObjects + // However it is not applicable for constructors with other parameters + + @TestSubject + private Discussion discussion; + + + // Mock objects need to be annotated with @Mock + @Mock + private Course courseMock; + + @Mock + private Comment commentMock; + + // TODO implement the tests + + @Test + public void testComment() { + // First we need to record + // Expect a function call and set a predetermined return value + // This expects the method to be called exactly once + expect(commentMock.save()).andReturn(true); + + // After setting all expectations we need to replay the mock - e.g set it so it behaves the way we recorded + replay(commentMock); + + // Test your objects as usual + discussion = new Discussion(); + assertEquals(0,discussion.getNumberOfComments()); + assertTrue(discussion.addComment(commentMock)); + assertEquals(1,discussion.getNumberOfComments()); + + // At the end you need to verify the mock - this checks whether the expected methods were actually called + verify(commentMock); + } + + // The methods below show the same usage + @Test + public void testCommentIfSavingFails() { + expect(commentMock.save()).andReturn(false); + replay(commentMock); + + discussion = new Discussion(); + assertEquals(0,discussion.getNumberOfComments()); + assertFalse(discussion.addComment(commentMock)); + assertEquals(0,discussion.getNumberOfComments()); + + verify(commentMock); + } + + @Test + public void testStartCourseDiscussion() { + Person person = new Lecturer("","",LocalDate.now()); + String testTopic = "testTopic"; + + expect(courseMock.isDiscussionAllowed(person)).andReturn(true); + + replay(courseMock); + assertTrue(discussion.startCourseDiscussion(courseMock,person,testTopic)); + assertEquals(courseMock,discussion.getCourse()); + assertEquals(testTopic,discussion.getTopic()); + + verify(courseMock); + } +``` + + +## Example with custom Constructor (also contains expecting *void* call) + +```java +@Mock +Platform platformMock; + +... + +@Test +public void addNoteGetsURIFromPlatform() throws URISyntaxException { + URI uri = URI.create("https://notes.tum.de/examplePath"); // An example uri your mock can return + String expectedWriteDataPath = uri.getPath(); // The path that the NotesServer should write to + + // Set the mock to expect the call and return the set URI + expect(platformMock.nextURI()).andReturn(uri); + + // To expect a void method call you can just call the method like usual before **replaying** the mock + platformMock.writeData(expectedWriteDataPath,"Some text"); + + // Replay the mock + replay(platformMock); + + // Instead of annotating with @TestSubject we instantiate the testServer(System Under Test) inside the Test + NotesServer testServer = new NotesServer(platformMock, false, false); + + // Test like usual + URI testUri = testServer.addNote("alice", "Some text"); + assertEquals(expectedWriteDataPath,testUri.getPath()); + + // At the end you need to verify the mock - this checks whether the expected methods were actually called + verify(platformMock); +} +``` + +## If you want multiple method invocations + + +| Method | Behaviour | +| ---------------- | -------------------------------------------------------------------------------------- | +| `.times(3)` | Expects the method to be called **exactly** 3 times. | +| `.times(2,5)` | Expects the method to be called between **2 and 5** times (inclusive). | +| `.atLeastOnce()` | Expects the method to be called **1 or more** times. | +| `.anyTimes()` | The method can be called **0 or more** times (it will never cause `verify()` to fail). | +For *void* methods: + +```java +commentMock.update(); // Call the void method +expectLastCall().times(3); // Set the invocation count +```
## ALL RESOURCE LINKS: @@ -794,3 +908,48 @@ public String displayPlaylist(int[] playlist) throws SpotifyClientException { - **man pages (command line, not online)**
+ +# DOCKER + +**Docker reference: https://docs.docker.com/** + +### Dockerfiles +https://docs.docker.com/get-started/docker-concepts/building-images/writing-a-dockerfile/ +https://docs.docker.com/reference/dockerfile/ + +```dockerfile +FROM python:3.13 +WORKDIR /usr/local/app + +# Install the application dependencies +COPY requirements.txt ./ +RUN pip install --no-cache-dir -r requirements.txt + +# Copy in the source code +COPY src ./src +EXPOSE 8080 + +# Setup an app user so the container doesn't run as the root user +RUN useradd app +USER app + +CMD ["uvicorn", "app.main:app", "--host", "0.0.0.0", "--port", "8080"] +``` + +### Building docker + +```bash +docker build -t +``` + +### Docker processes +```bash +docker ps +``` +#### Exercises +- [L09P01 - Registry Office Service Deployment](file:///home/nikola/Documents/EIST/eist26l09p01-go38coz) +- [L09P02 - Garching Best Software](file:///home/nikola/Documents/EIST/eist26l09p02-go38coz) +- [L08PE04 - Spaceship](file:///home/nikola/Documents/EIST/eist26l0pe04-go38coz) + +
+